home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / src / net / bind-contrib.tar.gz / bind-contrib.tar / contrib / host / host.c < prev    next >
C/C++ Source or Header  |  1996-11-10  |  196KB  |  7,867 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that: (1) source distributions retain this entire copyright
  7.  * notice and comment, and (2) distributions including binaries display
  8.  * the following acknowledgement:  ``This product includes software
  9.  * developed by the University of California, Berkeley and its contributors''
  10.  * in the documentation or other materials provided with the distribution
  11.  * and in all advertising materials mentioning features or use of this
  12.  * software. Neither the name of the University nor the names of its
  13.  * contributors may be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. /*
  21.  * Originally, this program came from Rutgers University, however it
  22.  * is based on nslookup and other pieces of named tools, so it needs
  23.  * that copyright notice.
  24.  */
  25.  
  26. /*
  27.  * Rewritten by Eric Wassenaar, Nikhef-H, <e07@nikhef.nl>
  28.  *
  29.  * The officially maintained source of this program is available
  30.  * via anonymous ftp from machine 'ftp.nikhef.nl' [192.16.199.1]
  31.  * in the directory '/pub/network' as 'host.tar.Z'
  32.  *
  33.  * You are kindly requested to report bugs and make suggestions
  34.  * for improvements to the author at the given email address,
  35.  * and to not re-distribute your own modifications to others.
  36.  */
  37.  
  38. #ifndef lint
  39. static char Version[] = "@(#)host.c    e07@nikhef.nl (Eric Wassenaar) 961013";
  40. #endif
  41.  
  42. #if defined(apollo) && defined(lint)
  43. #define __attribute(x)
  44. #endif
  45.  
  46. #define justfun            /* this is only for fun */
  47. #undef  obsolete        /* old code left as a reminder */
  48. #undef  notyet            /* new code for possible future use */
  49.  
  50. /*
  51.  *            New features
  52.  *
  53.  * - Major overhaul of the entire code.
  54.  * - Very rigid error checking, with more verbose error messages.
  55.  * - Zone listing section completely rewritten.
  56.  * - It is now possible to do recursive listings into delegated zones.
  57.  * - Maintain resource record statistics during zone listings.
  58.  * - Maintain count of hosts during zone listings.
  59.  * - Check for various extraneous conditions during zone listings.
  60.  * - Check for illegal domain names containing invalid characters.
  61.  * - Verify that certain domain names represent canonical host names.
  62.  * - Perform ttl consistency checking during zone listings.
  63.  * - Exploit multiple server addresses if available.
  64.  * - Option to exploit only primary server for zone transfers.
  65.  * - Option to exclude info from names that do not reside in a zone.
  66.  * - Implement timeout handling during connect and read.
  67.  * - Write resource record output to optional log file.
  68.  * - Special MB tracing by recursively expanding MR and MG records.
  69.  * - Special mode to check SOA records at each nameserver for a zone.
  70.  * - Special mode to check reverse mappings of host addresses.
  71.  * - Extended syntax allows multiple arguments on command line or stdin.
  72.  * - Configurable default options in HOST_DEFAULTS environment variable.
  73.  * - Implement new resource record types from RFC 1183 and 1348.
  74.  * - Basic experimental NSAP support as defined in RFC 1637.
  75.  * - Implement new resource record types from RFC 1664 and 1712.
  76.  * - Implement new resource record types from RFC 1876 and 1886.
  77.  * - Code is extensively documented.
  78.  */
  79.  
  80. /*
  81.  *            Publication history
  82.  *
  83.  * This information has been moved to the RELEASE_NOTES file.
  84.  */
  85.  
  86. /*
  87.  *            Compilation options
  88.  *
  89.  * This program usually compiles without special compilation options,
  90.  * but for some platforms you may have to define special settings.
  91.  * See the Makefile and the header file port.h for details.
  92.  */
  93.  
  94. /*
  95.  *            Miscellaneous notes
  96.  *
  97.  * This program should be linked explicitly with the BIND resolver library
  98.  * in case the default gethostbyname() or gethostbyaddr() routines use a
  99.  * non-standard strategy for retrieving information. These functions in the
  100.  * resolver library call on the nameserver, and fall back on the hosts file
  101.  * only if no nameserver is running (ECONNREFUSED).
  102.  *
  103.  * You may also want to link this program with the BIND resolver library if
  104.  * your default library has not been compiled with DEBUG printout enabled.
  105.  *
  106.  * The version of the resolver should be BIND 4.8.2 or later. The crucial
  107.  * include files are <netdb.h>, (resolv.h>, <arpa/nameser.h>. These files
  108.  * are assumed to be present in the /usr/include directory.
  109.  *
  110.  * The resolver code depends on the definition of the BSD pre-processor
  111.  * variable. This variable is usually defined in the file <sys/param.h>.
  112.  *
  113.  * The definition of this variable determines the method how to handle
  114.  * datagram connections. This may not work properly on all platforms.
  115.  *
  116.  * The hostent struct defined in <netdb.h> is assumed to handle multiple
  117.  * addresses in h_addr_list[]. Usually this is true if BSD >= 43.
  118.  *
  119.  * Your nameserver may not handle queries about top-level zones properly
  120.  * if the "domain" directive is present in the named.boot file. It will
  121.  * append the default domain to single names for which no data is cached.
  122.  *
  123.  * The treatment of TXT records has changed from 4.8.2 to 4.8.3. Formerly,
  124.  * the data consisted simply of the text string. Now, the text string is
  125.  * preceded by the character count with a maximum of 255, and multiple
  126.  * strings are embedded if the total character count exceeds 255.
  127.  * We handle only the new situation in this program, assuming that nobody
  128.  * uses TXT records before 4.8.3 (unfortunately this is not always true:
  129.  * current vendor supplied software may sometimes be even pre-BIND 4.8.2).
  130.  *
  131.  * Note that in 4.8.3 PACKETSZ from nameser.h is still at 512, which is
  132.  * the maximum possible packet size for datagrams, whereas MAXDATA from
  133.  * db.h has increased from 256 to 2048. The resolver defines MAXPACKET
  134.  * as 1024. The nameserver reads queries in a buffer of size BUFSIZ.
  135.  *
  136.  * The gethostbyname() routine in 4.8.3 interprets dotted quads (if not
  137.  * terminated with a dot) and simulates a gethostbyaddr(), but we will
  138.  * not rely on it, and handle dotted quads ourselves.
  139.  *
  140.  * On some systems a bug in the _doprnt() routine exists which prevents
  141.  * printf("%.*s", n, string) to be printed correctly if n == 0.
  142.  *
  143.  * This program has not been optimized for speed. Especially the memory
  144.  * management is simple and straightforward.
  145.  */
  146.  
  147. /*
  148.  *            Terminology used
  149.  *
  150.  * Gateway hosts.
  151.  * These are hosts that have more than one address registered under
  152.  * the same name. Obviously we cannot recognize a gateway host if it
  153.  * has different names associated with its different addresses.
  154.  *
  155.  * Duplicate hosts.
  156.  * These are non-gateway hosts of which the address was found earlier
  157.  * but with a different name, possibly in a totally different zone.
  158.  * Such hosts should not be counted again in the overall host count.
  159.  * This situation notably occurs in e.g. the "ac.uk" domain which has
  160.  * many names registered in both the long and the abbreviated form,
  161.  * such as 'host.department.university.ac.uk' and 'host.dept.un.ac.uk'.
  162.  * This is probably not an error per se. It is an error if some domain
  163.  * has registered a foreign address under a name within its own domain.
  164.  * To recognize duplicate hosts when traversing many zones, we have to
  165.  * maintain a global list of host addresses. To simplify things, only
  166.  * single-address hosts are handled as such.
  167.  *
  168.  * Extrazone hosts.
  169.  * These are hosts which belong to a zone but which are not residing
  170.  * directly within the zone under consideration and which are not
  171.  * glue records for a delegated zone of the given zone. E.g. if we are
  172.  * processing the zone 'bar' and find 'host.foo.bar' but 'foo.bar' is not
  173.  * an NS registered delegated zone of 'bar' then it is considered to be
  174.  * an extrazone host. This is not necessarily an error, but it could be.
  175.  *
  176.  * Lame delegations.
  177.  * If we query the SOA record of a zone at a supposedly authoritative
  178.  * nameserver for that zone (listed in the NS records for the zone),
  179.  * the SOA record should be present and the answer authoritative.
  180.  * If not, we flag a lame delegation of the zone to that nameserver.
  181.  * This may need refinement in some special cases.
  182.  * A lame delegation is also flagged if we discover that a nameserver
  183.  * mentioned in an NS record does not exist when looking up its address.
  184.  *
  185.  * Primary nameserver.
  186.  * This utility assumes that the first domain name in the RHS of the
  187.  * SOA record for a zone contains the name of the primary nameserver
  188.  * (or one of the primary nameservers) for that zone. Unfortunately,
  189.  * this field has not been unambiguously defined. Nevertheless, many
  190.  * hostmasters interpret the definitions given in RFC 1033 and 1035
  191.  * as such, and therefore host will continue doing so. Interpretation
  192.  * as the machine that holds the zone data disk file is pretty useless.
  193.  */
  194.  
  195. /*
  196.  *        Usage: host [options] name [server]
  197.  *        Usage: host [options] -x [name ...]
  198.  *        Usage: host [options] -X server [name ...]
  199.  *
  200.  * Regular command line options:
  201.  * ----------------------------
  202.  *
  203.  * -t type    specify query type; default is T_A for normal mode
  204.  * -a        specify query type T_ANY
  205.  * -v        print verbose messages (-vv is very verbose)
  206.  * -d        print debugging output (-dd prints even more)
  207.  *
  208.  * Special mode options.
  209.  * --------------------
  210.  *
  211.  * -l        special mode to generate zone listing for a zone
  212.  * -L level    do recursive zone listing/checking this level deep
  213.  * -p        use primary nameserver of zone for zone transfers
  214.  * -P server    give priority to preferred servers for zone transfers
  215.  * -N zone    do not perform zone transfer for these explicit zones
  216.  * -S        print zone resource record statistics
  217.  * -H        special mode to count hosts residing in a zone
  218.  * -G        same as -H but lists gateway hosts in addition
  219.  * -E        same as -H but lists extrazone hosts in addition
  220.  * -D        same as -H but lists duplicate hosts in addition
  221.  * -C        special mode to check SOA records for a zone
  222.  * -A        special mode to check reverse mappings of host addresses
  223.  *
  224.  * Miscellaneous options.
  225.  * ---------------------
  226.  *
  227.  * -f filename    log resource record output also in given file
  228.  * -F filename    same as -f, but exchange role of stdout and log file
  229.  * -I chars    chars are not considered illegal in domain names
  230.  * -i        generate reverse in-addr.arpa query for dotted quad
  231.  * -n        generate reverse nsap.int query for dotted nsap address
  232.  * -q        be quiet about some non-fatal errors
  233.  * -T        print ttl value during non-verbose output
  234.  * -Z        print selected RR output in full zone file format
  235.  *
  236.  * Seldom used options.
  237.  * -------------------
  238.  *
  239.  * -c class    specify query class; default is C_IN
  240.  * -e        exclude info from names that do not reside in the zone
  241.  * -m        specify query type T_MAILB and trace MB records
  242.  * -o        suppress resource record output to stdout
  243.  * -r        do not use recursion when querying nameserver
  244.  * -R        repeatedly add search domains to qualify queryname
  245.  * -s secs    specify timeout value in seconds; default is 2 * 5
  246.  * -u        use virtual circuit instead of datagram for queries
  247.  * -w        wait until nameserver becomes available
  248.  *
  249.  * Undocumented options. (Experimental, subject to change)
  250.  * --------------------
  251.  *
  252.  * -g length    only select names that are at least this long
  253.  * -B        enforce full BIND behavior during DNSRCH
  254.  * -M        special mode to list mailable delegated zones of zone
  255.  * -W        special mode to list wildcard records in a zone
  256.  * -z        special mode to list delegated zones in a zone
  257.  */
  258.  
  259. static char Usage[] =
  260. "\
  261. Usage:      host [-v] [-a] [-t querytype] [options]  name  [server]\n\
  262. Listing:    host [-v] [-a] [-t querytype] [options]  -l zone  [server]\n\
  263. Hostcount:  host [-v] [options] -H [-D] [-E] [-G] zone\n\
  264. Check soa:  host [-v] [options] -C zone\n\
  265. Addrcheck:  host [-v] [options] -A host\n\
  266. Listing options: [-L level] [-S] [-A] [-p] [-P prefserver] [-N skipzone]\n\
  267. Common options:  [-d] [-f|-F filename] [-I chars] [-i|-n] [-q] [-T] [-Z]\n\
  268. Other options:   [-c class] [-e] [-m] [-o] [-r] [-R] [-s secs] [-u] [-w]\n\
  269. Extended usage:  [-x [name ...]] [-X server [name ...]]\
  270. ";
  271.  
  272. #include <stdio.h>
  273. #include <ctype.h>
  274. #include <errno.h>
  275. #include <netdb.h>
  276. #include <time.h>
  277.  
  278. #include <sys/types.h>        /* not always automatically included */
  279. #include <sys/param.h>
  280. #include <sys/socket.h>
  281. #include <netinet/in.h>
  282.  
  283. #undef NOERROR            /* in <sys/streams.h> on solaris 2.x */
  284. #include <arpa/nameser.h>
  285. #include <resolv.h>
  286.  
  287. #include "port.h"        /* various portability definitions */
  288. #include "conf.h"        /* various configuration definitions */
  289. #include "type.h"        /* types should be in <arpa/nameser.h> */
  290. #include "exit.h"        /* exit codes come from <sysexits.h> */
  291.  
  292. typedef int    bool;        /* boolean type */
  293. #define TRUE    1
  294. #define FALSE    0
  295.  
  296. #ifndef NO_DATA
  297. #define NO_DATA    NO_ADDRESS    /* used here only in case authoritative */
  298. #endif
  299.  
  300. #define NO_RREC    (NO_DATA + 1)    /* used for non-authoritative NO_DATA */
  301. #define NO_HOST    (NO_DATA + 2)    /* used for non-authoritative HOST_NOT_FOUND */
  302.  
  303. #define QUERY_REFUSED  (NO_DATA + 3)    /* query was refused by server */
  304. #define SERVER_FAILURE (NO_DATA + 4)    /* instead of TRY_AGAIN upon SERVFAIL */
  305. #define HOST_NOT_CANON (NO_DATA + 5)    /* host name is not canonical */
  306.  
  307. #define T_NONE    0        /* yet unspecified resource record type */
  308. #define T_FIRST    T_A        /* first possible type in resource record */
  309. #define T_LAST    (T_IXFR - 1)    /* last  possible type in resource record */
  310.  
  311. #ifndef NOCHANGE
  312. #define NOCHANGE 0xf        /* compatibility with older BIND versions */
  313. #endif
  314.  
  315. #define NOT_DOTTED_QUAD    ((ipaddr_t)-1)
  316. #define BROADCAST_ADDR    ((ipaddr_t)0xffffffff)
  317. #define LOCALHOST_ADDR    ((ipaddr_t)0x7f000001)
  318.  
  319. #if PACKETSZ > 8192
  320. #define MAXPACKET PACKETSZ    /* PACKETSZ should be the max udp size (512) */
  321. #else
  322. #define MAXPACKET 8192        /* but tcp packets can be considerably larger */
  323. #endif
  324.  
  325. typedef union {
  326.     HEADER header;
  327.     u_char packet[MAXPACKET];
  328. } querybuf;
  329.  
  330. #ifndef HFIXEDSZ
  331. #define HFIXEDSZ 12        /* actually sizeof(HEADER) */
  332. #endif
  333.  
  334. #define MAXDLEN (MAXPACKET - HFIXEDSZ)    /* upper bound for dlen */
  335.  
  336. #include "rrec.h"        /* resource record structures */
  337.  
  338. #define input            /* read-only input parameter */
  339. #define output            /* modified output parameter */
  340.  
  341. #define STDIN    0
  342. #define STDOUT    1
  343. #define STDERR    2
  344.  
  345. #ifdef lint
  346. #define EXTERN
  347. #else
  348. #define EXTERN extern
  349. #endif
  350.  
  351. EXTERN int errno;
  352. EXTERN int h_errno;        /* defined in the resolver library */
  353. EXTERN res_state_t _res;    /* defined in res_init.c */
  354. extern char *dbprefix;        /* prefix for debug messages (send.c) */
  355. extern char *version;        /* program version number (vers.c) */
  356.  
  357. char **optargv = NULL;        /* argument list including default options */
  358. int optargc = 0;        /* number of arguments in new argument list */
  359.  
  360. int errorcount = 0;        /* global error count */
  361.  
  362. int record_stats[T_ANY+1];    /* count of resource records per type */
  363.  
  364. char cnamebuf[MAXDNAME+1];
  365. char *cname = NULL;        /* RHS name to which CNAME is aliased */
  366. char mnamebuf[MAXDNAME+1];
  367. char *mname = NULL;        /* RHS name to which MR or MG is aliased */
  368. char soanamebuf[MAXDNAME+1];
  369. char *soaname = NULL;        /* LHS domain name of SOA record */
  370. char subnamebuf[MAXDNAME+1];
  371. char *subname = NULL;        /* LHS domain name of NS record */
  372. char adrnamebuf[MAXDNAME+1];
  373. char *adrname = NULL;        /* LHS domain name of A record */
  374.  
  375. ipaddr_t address;        /* internet address of A record */
  376.  
  377. char *listhost = NULL;        /* actual host queried during zone listing */
  378.  
  379. char serverbuf[MAXDNAME+1];
  380. char *server = NULL;        /* name of explicit server to query */
  381.  
  382. char realnamebuf[2*MAXDNAME+2];
  383. char *realname = NULL;        /* the actual name that was queried */
  384.  
  385. FILE *logfile = NULL;        /* default is stdout only */
  386. bool logexchange = FALSE;    /* exchange role of log file and stdout */
  387.  
  388. char *illegal = NULL;        /* give warning about illegal domain names */
  389. char *skipzone = NULL;        /* zone(s) for which to skip zone transfer */
  390. char *prefserver = NULL;    /* preferred server(s) for zone listing */
  391.  
  392. char *queryname = NULL;        /* the name about which to query */
  393. int querytype = T_NONE;        /* the type of the query */
  394. int queryclass = C_IN;        /* the class of the query */
  395. ipaddr_t queryaddr;        /* set if name to query is dotted quad */
  396.  
  397. int debug = 0;            /* print resolver debugging output */
  398. int verbose = 0;        /* verbose mode for extra output */
  399.  
  400. #ifdef justfun
  401. int namelen = 0;        /* select records exceeding this length */
  402. #endif
  403.  
  404. int recursive = 0;        /* recursive listmode maximum level */
  405. int recursion_level = 0;    /* current recursion level */
  406. int skip_level = 0;        /* level beyond which to skip checks */
  407. int print_level = 0;        /* level below which to skip verbose output */
  408.  
  409. bool quiet = FALSE;        /* suppress non-fatal warning messages */
  410. bool reverse = FALSE;        /* generate reverse in-addr.arpa queries */
  411. bool revnsap = FALSE;        /* generate reverse nsap.int queries */
  412. bool primary = FALSE;        /* use primary server for zone transfers */
  413. bool suppress = FALSE;        /* suppress resource record output */
  414. bool dotprint = FALSE;        /* print trailing dot in non-listing mode */
  415. bool ttlprint = FALSE;        /* print ttl value in non-verbose mode */
  416. bool waitmode = FALSE;        /* wait until server becomes available */
  417. bool mailmode = FALSE;        /* trace MG and MR into MB records */
  418. bool addrmode = FALSE;        /* check reverse mappings of addresses */
  419. bool listmode = FALSE;        /* generate zone listing of a zone */
  420. bool hostmode = FALSE;        /* count real hosts residing within zone */
  421. bool duplmode = FALSE;        /* list duplicate hosts within zone */
  422. bool extrmode = FALSE;        /* list extrazone hosts within zone */
  423. bool gatemode = FALSE;        /* list gateway hosts within zone */
  424. bool checkmode = FALSE;        /* check SOA records at each nameserver */
  425. bool mxdomains = FALSE;        /* list MX records for each delegated zone */
  426. bool wildcards = FALSE;        /* list only wildcard records in a zone */
  427. bool listzones = FALSE;        /* list only delegated zones in a zone */
  428. bool exclusive = FALSE;        /* exclude records that are not in zone */
  429. bool recurskip = FALSE;        /* skip certain checks during recursion */
  430. bool statistics = FALSE;    /* print resource record statistics */
  431. bool bindcompat = FALSE;    /* enforce full BIND DNSRCH compatibility */
  432. bool classprint = FALSE;    /* print class value in non-verbose mode */
  433.  
  434. #include "defs.h"        /* declaration of functions */
  435.  
  436. #define is_xdigit(c)    (isascii(c) && isxdigit(c))
  437. #define is_space(c)    (isascii(c) && isspace(c))
  438. #define is_alnum(c)    (isascii(c) && isalnum(c))
  439. #define is_upper(c)    (isascii(c) && isupper(c))
  440.  
  441. #define lowercase(c)    (is_upper(c) ? tolower(c) : (c))
  442. #define lower(c)    (((c) >= 'A' && (c) <= 'Z') ? (c) + 'a' - 'A' : (c))
  443. #define hexdigit(n)    (((n) < 10) ? '0' + (n) : 'A' + (n) - 10);
  444.  
  445. #define bitset(a,b)    (((a) & (b)) != 0)
  446. #define sameword(a,b)    (strcasecmp(a,b) == 0)
  447. #define samepart(a,b)    (strncasecmp(a,b,strlen(b)) == 0)
  448. #define samehead(a,b)    (strncasecmp(a,b,sizeof(b)-1) == 0)
  449.  
  450. #define fakename(a)    (samehead(a,"localhost.") || samehead(a,"loopback."))
  451. #define nulladdr(a)    (((a) == 0) || ((a) == BROADCAST_ADDR))
  452. #define fakeaddr(a)    (nulladdr(a) || ((a) == htonl(LOCALHOST_ADDR)))
  453. #define incopy(a)    *((struct in_addr *)(a))
  454. #define querysize(n)    (((n) > sizeof(querybuf)) ? sizeof(querybuf) : (n))
  455.  
  456. #define newlist(a,n,t)    (t *)xalloc((ptr_t *)(a), (siz_t)((n)*sizeof(t)))
  457. #define newstruct(t)    (t *)xalloc((ptr_t *)NULL, (siz_t)(sizeof(t)))
  458. #define newstring(s)    (char *)xalloc((ptr_t *)NULL, (siz_t)(strlen(s)+1))
  459. #define newstr(s)    strcpy(newstring(s), s)
  460. #define xfree(a)    (void) free((ptr_t *)(a))
  461.  
  462. #define strlength(s)    (int)strlen(s)
  463. #define in_string(s,c)    (index(s,c) != NULL)
  464. #define is_quoted(a,b)    (((a) > (b)) && ((a)[-1] == '\\'))
  465.  
  466. #define plural(n)    (((n) == 1) ? "" : "s")
  467. #define plurale(n)    (((n) == 1) ? "" : "es")
  468.  
  469. #ifdef DEBUG
  470. #define assert(condition)\
  471. {\
  472.     if (!(condition))\
  473.     {\
  474.         (void) fprintf(stderr, "assertion botch: ");\
  475.         (void) fprintf(stderr, "%s(%d): ", __FILE__, __LINE__);\
  476.         (void) fprintf(stderr, "%s\n", "condition");\
  477.         exit(EX_SOFTWARE);\
  478.     }\
  479. }
  480. #else
  481. #define assert(condition)
  482. #endif
  483.  
  484. /*
  485. ** MAIN -- Start of program host
  486. ** -----------------------------
  487. **
  488. **    Exits:
  489. **        EX_SUCCESS    Operation successfully completed
  490. **        EX_UNAVAILABLE    Could not obtain requested information
  491. **        EX_CANTCREAT    Could not create specified log file
  492. **        EX_NOINPUT    No input arguments were found
  493. **        EX_NOHOST    Could not lookup explicit server
  494. **        EX_OSERR    Could not obtain resources
  495. **        EX_USAGE    Improper parameter/option specified
  496. **        EX_SOFTWARE    Assertion botch in DEBUG mode
  497. */
  498.  
  499. int
  500. main(argc, argv)
  501. input int argc;
  502. input char *argv[];
  503. {
  504.     register char *option;
  505.     res_state_t new_res;        /* new resolver database */
  506.     int result;            /* result status of action taken */
  507.     char *program;            /* name that host was called with */
  508.     char *servername = NULL;    /* name of explicit server */
  509.     char *logfilename = NULL;    /* name of log file */
  510.     bool extended = FALSE;        /* accept extended argument syntax */
  511.  
  512.     assert(sizeof(int) >= 4);    /* probably paranoid */
  513. #ifdef obsolete
  514.     assert(sizeof(u_short) == 2);    /* perhaps less paranoid */
  515.     assert(sizeof(ipaddr_t) == 4);    /* but this is critical */
  516. #endif
  517.  
  518. /*
  519.  * Synchronize stdout and stderr in case output is redirected.
  520.  */
  521.     linebufmode(stdout);
  522.  
  523. /*
  524.  * Initialize resolver, set new defaults. See show_res() for details.
  525.  * The old defaults are (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
  526.  */
  527.     (void) res_init();
  528.  
  529.     _res.options |=  RES_DEFNAMES;    /* qualify single names */
  530.     _res.options &= ~RES_DNSRCH;    /* dotted names are qualified */
  531.  
  532.     _res.options |=  RES_RECURSE;    /* request nameserver recursion */
  533.     _res.options &= ~RES_DEBUG;    /* turn off debug printout */
  534.     _res.options &= ~RES_USEVC;    /* do not use virtual circuit */
  535.  
  536.     _res.retry = DEF_RETRIES;    /* number of datagram retries */
  537.     _res.retrans = DEF_RETRANS;    /* timeout in secs between retries */
  538.  
  539.     /* initialize packet id */
  540.     _res.id = getpid() & 0x7fff;
  541.  
  542.     /* save new defaults */
  543.     new_res = _res;
  544.  
  545. /*
  546.  * Check whether host was called with a different name.
  547.  * Interpolate default options and parameters.
  548.  */
  549.     if (argc < 1 || argv[0] == NULL)
  550.         fatal(Usage);
  551.  
  552.     option = getenv("HOST_DEFAULTS");
  553.     if (option != NULL)
  554.     {
  555.         set_defaults(option, argc, argv);
  556.         argc = optargc; argv = optargv;
  557.     }
  558.  
  559.     program = rindex(argv[0], '/');
  560.     if (program++ == NULL)
  561.         program = argv[0];
  562.  
  563.     /* check for resource record names */
  564.     querytype = parse_type(program);
  565.     if (querytype < 0)
  566.         querytype = T_NONE;
  567.  
  568.     /* check for zone listing abbreviation */
  569.     if (sameword(program, "zone"))
  570.         listmode = TRUE;
  571.  
  572. /*
  573.  * Scan command line options and flags.
  574.  */
  575.     while (argc > 1 && argv[1] != NULL && argv[1][0] == '-')
  576.     {
  577.         for (option = &argv[1][1]; *option != '\0'; option++)
  578.         {
  579.         switch (*option)
  580.         {
  581.             case 'w' :
  582.             waitmode = TRUE;
  583.             new_res.retry = DEF_RETRIES;
  584.             new_res.retrans = DEF_RETRANS;
  585.             break;
  586.  
  587.             case 's' :
  588.             if (argv[2] == NULL || argv[2][0] == '-')
  589.                 fatal("Missing timeout value");
  590.             new_res.retry = DEF_RETRIES;
  591.             new_res.retrans = atoi(argv[2]);
  592.             if (new_res.retrans <= 0)
  593.                 fatal("Invalid timeout value %s", argv[2]);
  594.             argv++; argc--;
  595.             break;
  596.  
  597.             case 'r' :
  598.             new_res.options &= ~RES_RECURSE;
  599.             break;
  600.  
  601.             case 'B' :
  602.             bindcompat = TRUE;
  603.             /*FALLTHROUGH*/
  604.  
  605.             case 'R' :
  606.             new_res.options |= RES_DNSRCH;
  607.             break;
  608.  
  609.             case 'u' :
  610.             new_res.options |= RES_USEVC;
  611.             break;
  612.  
  613.             case 'd' :
  614.             new_res.options |= RES_DEBUG;
  615.             debug++;        /* increment debugging level */
  616.             break;
  617.  
  618.             case 'v' :
  619.             verbose++;        /* increment verbosity level */
  620.             break;
  621.  
  622.             case 'q' :
  623.             quiet = TRUE;
  624.             break;
  625.  
  626.             case 'i' :
  627.             reverse = TRUE;
  628.             break;
  629.  
  630.             case 'n' :
  631.             revnsap = TRUE;
  632.             break;
  633.  
  634.             case 'p' :
  635.             primary = TRUE;
  636.             break;
  637.  
  638.             case 'o' :
  639.             suppress = TRUE;
  640.             break;
  641.  
  642.             case 'e' :
  643.             exclusive = TRUE;
  644.             break;
  645.  
  646.             case 'S' :
  647.             statistics = TRUE;
  648.             break;
  649.  
  650.             case 'T' :
  651.             ttlprint = TRUE;
  652.             break;
  653.  
  654.             case 'Z' :
  655.             dotprint = TRUE;
  656.             ttlprint = TRUE;
  657.             classprint = TRUE;
  658.             break;
  659.  
  660.             case 'A' :
  661.             addrmode = TRUE;
  662.             break;
  663.  
  664.             case 'D' :
  665.             case 'E' :
  666.             case 'G' :
  667.             case 'H' :
  668.             if (*option == 'D')
  669.                 duplmode = TRUE;
  670.             if (*option == 'E')
  671.                 extrmode = TRUE;
  672.             if (*option == 'G')
  673.                 gatemode = TRUE;
  674.             hostmode = TRUE;
  675.             listmode = TRUE;
  676.             if (querytype == T_NONE)
  677.                 querytype = -1;    /* suppress zone data output */
  678.             break;
  679.  
  680.             case 'C' :
  681.             checkmode = TRUE;
  682.             listmode = TRUE;
  683.             if (querytype == T_NONE)
  684.                 querytype = -1;    /* suppress zone data output */
  685.             break;
  686.  
  687.             case 'z' :
  688.             listzones = TRUE;
  689.             listmode = TRUE;
  690.             if (querytype == T_NONE)
  691.                 querytype = -1;    /* suppress zone data output */
  692.             break;
  693.  
  694.             case 'M' :
  695.             mxdomains = TRUE;
  696.             listmode = TRUE;
  697.             if (querytype == T_NONE)
  698.                 querytype = -1;    /* suppress zone data output */
  699.             break;
  700.  
  701.             case 'W' :
  702.             wildcards = TRUE;
  703.             listmode = TRUE;
  704.             if (querytype == T_NONE)
  705.                 querytype = T_MX;
  706.             break;
  707.  
  708.             case 'L' :
  709.             if (argv[2] == NULL || argv[2][0] == '-')
  710.                 fatal("Missing recursion level");
  711.             recursive = atoi(argv[2]);
  712.             if (recursive <= 0)
  713.                 fatal("Invalid recursion level %s", argv[2]);
  714.             argv++; argc--;
  715.             /*FALLTHROUGH*/
  716.  
  717.             case 'l' :
  718.             listmode = TRUE;
  719.             break;
  720.  
  721.             case 'c' :
  722.             if (argv[2] == NULL || argv[2][0] == '-')
  723.                 fatal("Missing query class");
  724.             queryclass = parse_class(argv[2]);
  725.             if (queryclass < 0)
  726.                 fatal("Invalid query class %s", argv[2]);
  727.             argv++; argc--;
  728.             break;
  729.  
  730.             case 't' :
  731.             if (argv[2] == NULL || argv[2][0] == '-')
  732.                 fatal("Missing query type");
  733.             querytype = parse_type(argv[2]);
  734.             if (querytype < 0)
  735.                 fatal("Invalid query type %s", argv[2]);
  736.             argv++; argc--;
  737.             break;
  738.  
  739.             case 'a' :
  740.             querytype = T_ANY;    /* filter anything available */
  741.             break;
  742.  
  743.             case 'm' :
  744.             mailmode = TRUE;
  745.             querytype = T_MAILB;    /* filter MINFO/MG/MR/MB data */
  746.             break;
  747.  
  748.             case 'I' :
  749.             if (argv[2] == NULL || argv[2][0] == '-')
  750.                 fatal("Missing allowed chars");
  751.             illegal = argv[2];
  752.             argv++; argc--;
  753.             break;
  754.  
  755.             case 'P' :
  756.             if (argv[2] == NULL || argv[2][0] == '-')
  757.                 fatal("Missing preferred server");
  758.             prefserver = argv[2];
  759.             argv++; argc--;
  760.             break;
  761.  
  762.             case 'N' :
  763.             if (argv[2] == NULL || argv[2][0] == '-')
  764.                 fatal("Missing zone to be skipped");
  765.             skipzone = argv[2];
  766.             argv++; argc--;
  767.             break;
  768.  
  769.             case 'F' :
  770.             logexchange = TRUE;
  771.             /*FALLTHROUGH*/
  772.  
  773.             case 'f' :
  774.             if (argv[2] == NULL || argv[2][0] == '-')
  775.                 fatal("Missing log file name");
  776.             logfilename = argv[2];
  777.             argv++; argc--;
  778.             break;
  779.  
  780.             case 'X' :
  781.             if (argv[2] == NULL || argv[2][0] == '-')
  782.                 fatal("Missing server name");
  783.             servername = argv[2];
  784.             argv++; argc--;
  785.             /*FALLTHROUGH*/
  786.  
  787.             case 'x' :
  788.             extended = TRUE;
  789.             break;
  790. #ifdef justfun
  791.             case 'g' :
  792.             if (argv[2] == NULL || argv[2][0] == '-')
  793.                 fatal("Missing minimum length");
  794.             namelen = atoi(argv[2]);
  795.             if (namelen <= 0)
  796.                 fatal("Invalid minimum length %s", argv[2]);
  797.             argv++; argc--;
  798.             break;
  799. #endif
  800.             case 'V' :
  801.             printf("Version %s\n", version);
  802.             exit(EX_SUCCESS);
  803.  
  804.             default:
  805.             fatal(Usage);
  806.         }
  807.         }
  808.  
  809.         argv++; argc--;
  810.     }
  811.  
  812. /*
  813.  * Check the remaining arguments.
  814.  */
  815.     /* old syntax must have at least one argument */
  816.     if (!extended && (argc < 2 || argv[1] == NULL || argc > 3))
  817.         fatal(Usage);
  818.  
  819.     /* old syntax has explicit server as second argument */
  820.     if (!extended && (argc > 2 && argv[2] != NULL))
  821.         servername = argv[2];
  822.  
  823. /*
  824.  * Open log file if requested.
  825.  */
  826.     if (logfilename != NULL)
  827.         set_logfile(logfilename);
  828.  
  829. /*
  830.  * Set default preferred server for zone listings, if not specified.
  831.  */
  832.     if (listmode && (prefserver == NULL))
  833.         prefserver = myhostname();
  834.  
  835. /*
  836.  * Check for possible alternative server. Use new resolver defaults.
  837.  */
  838.     if (servername != NULL)
  839.         set_server(servername);
  840.  
  841. /*
  842.  * Do final resolver initialization.
  843.  * Show resolver parameters and special environment options.
  844.  */
  845.     /* set new resolver values changed by command options */
  846.     _res.retry = new_res.retry;
  847.     _res.retrans = new_res.retrans;
  848.     _res.options = new_res.options;
  849.  
  850.     /* show the new resolver database */
  851.     if (verbose > 1 || debug > 1)
  852.         show_res();
  853.  
  854.     /* show customized default domain */
  855.     option = getenv("LOCALDOMAIN");
  856.     if (option != NULL && verbose > 1)
  857.         printf("Explicit local domain %s\n\n", option);
  858.  
  859. /*
  860.  * Process command line argument(s) depending on syntax.
  861.  */
  862.     if (!extended) /* only one argument */
  863.         result = process_name(argv[1]);
  864.  
  865.     else if (argc < 2) /* no arguments */
  866.         result = process_file(stdin);
  867.  
  868.     else /* multiple command line arguments */
  869.         result = process_argv(argc, argv);
  870.  
  871. /*
  872.  * Report result status of action taken.
  873.  */
  874.     exit(result);
  875.     /*NOTREACHED*/
  876. }
  877.  
  878. /*
  879. ** SET_DEFAULTS -- Interpolate default options and parameters in argv
  880. ** ------------------------------------------------------------------
  881. **
  882. **    The HOST_DEFAULTS environment variable gives customized options.
  883. **
  884. **    Returns:
  885. **        None.
  886. **
  887. **    Outputs:
  888. **        Creates ``optargv'' vector with ``optargc'' arguments.
  889. */
  890.  
  891. void
  892. set_defaults(option, argc, argv)
  893. input char *option;            /* option string */
  894. input int argc;                /* original command line arg count */
  895. input char *argv[];            /* original command line arguments */
  896. {
  897.     register char *p, *q;
  898.     register int i;
  899.  
  900. /*
  901.  * Allocate new argument vector.
  902.  */
  903.     optargv = newlist(NULL, 2, char *);
  904.     optargv[0] = argv[0];
  905.     optargc = 1;
  906.  
  907. /*
  908.  * Construct argument list from option string.
  909.  */
  910.     for (q = "", p = newstr(option); *p != '\0'; p = q)
  911.     {
  912.         while (is_space(*p))
  913.             p++;
  914.  
  915.         if (*p == '\0')
  916.             break;
  917.  
  918.         for (q = p; *q != '\0' && !is_space(*q); q++)
  919.             continue;
  920.  
  921.         if (*q != '\0')
  922.             *q++ = '\0';
  923.  
  924.         optargv = newlist(optargv, optargc+2, char *);
  925.         optargv[optargc] = p;
  926.         optargc++;
  927.     }
  928.  
  929. /*
  930.  * Append command line arguments.
  931.  */
  932.     for (i = 1; i < argc && argv[i] != NULL; i++)
  933.     {
  934.         optargv = newlist(optargv, optargc+2, char *);
  935.         optargv[optargc] = argv[i];
  936.         optargc++;
  937.     }
  938.  
  939.     /* and terminate */
  940.     optargv[optargc] = NULL;
  941. }
  942.  
  943. /*
  944. ** PROCESS_ARGV -- Process command line arguments
  945. ** ----------------------------------------------
  946. **
  947. **    Returns:
  948. **        EX_SUCCESS if information was obtained successfully.
  949. **        Appropriate exit code otherwise.
  950. */
  951.  
  952. int
  953. process_argv(argc, argv)
  954. input int argc;
  955. input char *argv[];
  956. {
  957.     register int i;
  958.     int result;            /* result status of action taken */
  959.     int excode = EX_NOINPUT;    /* overall result status */
  960.  
  961.     for (i = 1; i < argc && argv[i] != NULL; i++)
  962.     {
  963.         /* process a single argument */
  964.         result = process_name(argv[i]);
  965.  
  966.         /* maintain overall result */
  967.         if (result != EX_SUCCESS || excode == EX_NOINPUT)
  968.             excode = result;
  969.     }
  970.  
  971.     /* return overall result */
  972.     return(excode);
  973. }
  974.  
  975. /*
  976. ** PROCESS_FILE -- Process arguments from input file
  977. ** -------------------------------------------------
  978. **
  979. **    Returns:
  980. **        EX_SUCCESS if information was obtained successfully.
  981. **        Appropriate exit code otherwise.
  982. */
  983.  
  984. int
  985. process_file(fp)
  986. input FILE *fp;                /* input file with query names */
  987. {
  988.     register char *p, *q;
  989.     char buf[BUFSIZ];
  990.     int result;            /* result status of action taken */
  991.     int excode = EX_NOINPUT;    /* overall result status */
  992.  
  993.     while (fgets(buf, sizeof(buf), fp) != NULL)
  994.     {
  995.         p = index(buf, '\n');
  996.         if (p != NULL)
  997.             *p = '\0';
  998.  
  999.         /* extract names separated by whitespace */
  1000.         for (q = "", p = buf; *p != '\0'; p = q)
  1001.         {
  1002.             while (is_space(*p))
  1003.                 p++;
  1004.  
  1005.             /* ignore comment lines */
  1006.             if (*p == '\0' || *p == '#' || *p == ';')
  1007.                 break;
  1008.  
  1009.             for (q = p; *q != '\0' && !is_space(*q); q++)
  1010.                 continue;
  1011.  
  1012.             if (*q != '\0')
  1013.                 *q++ = '\0';
  1014.  
  1015.             /* process a single argument */
  1016.             result = process_name(p);
  1017.  
  1018.             /* maintain overall result */
  1019.             if (result != EX_SUCCESS || excode == EX_NOINPUT)
  1020.                 excode = result;
  1021.         }
  1022.     }
  1023.  
  1024.     /* return overall result */
  1025.     return(excode);
  1026. }
  1027.  
  1028. /*
  1029. ** PROCESS_NAME -- Process a single command line argument
  1030. ** ------------------------------------------------------
  1031. **
  1032. **    Returns:
  1033. **        EX_SUCCESS if information was obtained successfully.
  1034. **        Appropriate exit code otherwise.
  1035. **
  1036. **    Wrapper for execute_name() to hide administrative tasks.
  1037. */
  1038.  
  1039. int
  1040. process_name(name)
  1041. input char *name;            /* command line argument */
  1042. {
  1043.     int result;            /* result status of action taken */
  1044.     static int save_querytype;
  1045.     static bool save_reverse;
  1046.     static bool firstname = TRUE;
  1047.  
  1048.     /* separate subsequent pieces of output */
  1049.     if (!firstname && (verbose || debug || checkmode))
  1050.         printf("\n");
  1051.  
  1052. /*
  1053.  * Some global variables are redefined further on. Save their initial
  1054.  * values in the first pass, and restore them during subsequent passes.
  1055.  */
  1056.     if (firstname)
  1057.     {
  1058.         save_querytype = querytype;
  1059.         save_reverse = reverse;
  1060.         firstname = FALSE;
  1061.     }
  1062.     else
  1063.     {
  1064.         querytype = save_querytype;
  1065.         reverse = save_reverse;
  1066.     }
  1067.  
  1068. /*
  1069.  * Do the real work.
  1070.  */
  1071.     result = execute_name(name);
  1072.     return(result);
  1073. }
  1074.  
  1075. /*
  1076. ** EXECUTE_NAME -- Process a single command line argument
  1077. ** ------------------------------------------------------
  1078. **
  1079. **    Returns:
  1080. **        EX_SUCCESS if information was obtained successfully.
  1081. **        Appropriate exit code otherwise.
  1082. **
  1083. **    Outputs:
  1084. **        Defines ``queryname'' and ``queryaddr'' appropriately.
  1085. **
  1086. **    Side effects:
  1087. **        May redefine ``querytype'' and ``reverse'' if necessary.
  1088. */
  1089.  
  1090. int
  1091. execute_name(name)
  1092. input char *name;            /* command line argument */
  1093. {
  1094.     bool result;            /* result status of action taken */
  1095.  
  1096.     /* check for nonsense input name */
  1097.     if (strlength(name) > MAXDNAME)
  1098.     {
  1099.         errmsg("Query name %s too long", name);
  1100.         return(EX_USAGE);
  1101.     }
  1102.  
  1103. /*
  1104.  * Analyze the name and type to be queried about.
  1105.  * The name can be an ordinary domain name, or an internet address
  1106.  * in dotted quad notation. If the -n option is given, the name is
  1107.  * supposed to be a dotted nsap address.
  1108.  * Furthermore, an empty input name is treated as the root domain.
  1109.  */
  1110.     queryname = name;
  1111.     if (queryname[0] == '\0')
  1112.         queryname = ".";
  1113.  
  1114.     if (sameword(queryname, "."))
  1115.         queryaddr = NOT_DOTTED_QUAD;
  1116.     else
  1117.         queryaddr = inet_addr(queryname);
  1118.  
  1119. /*
  1120.  * Generate reverse in-addr.arpa query if so requested.
  1121.  * The input name must be a dotted quad, and be convertible.
  1122.  */
  1123.     if (reverse)
  1124.     {
  1125.         if (queryaddr == NOT_DOTTED_QUAD)
  1126.             name = NULL;
  1127.         else
  1128.             name = in_addr_arpa(queryname);
  1129.  
  1130.         if (name == NULL)
  1131.         {
  1132.             errmsg("Invalid dotted quad %s", queryname);
  1133.             return(EX_USAGE);
  1134.         }
  1135.  
  1136.         /* redefine appropriately */
  1137.         queryname = name;
  1138.         queryaddr = NOT_DOTTED_QUAD;
  1139.     }
  1140.  
  1141. /*
  1142.  * Generate reverse nsap.int query if so requested.
  1143.  * The input name must be a dotted nsap, and be convertible.
  1144.  */
  1145.     if (revnsap)
  1146.     {
  1147.         if (reverse)
  1148.             name = NULL;
  1149.         else
  1150.             name = nsap_int(queryname);
  1151.  
  1152.         if (name == NULL)
  1153.         {
  1154.             errmsg("Invalid nsap address %s", queryname);
  1155.             return(EX_USAGE);
  1156.         }
  1157.  
  1158.         /* redefine appropriately */
  1159.         queryname = name;
  1160.         queryaddr = NOT_DOTTED_QUAD;
  1161.  
  1162.         /* this is also a reversed mapping domain */
  1163.         reverse = TRUE;
  1164.     }
  1165.  
  1166. /*
  1167.  * In regular mode, the querytype is used to formulate the nameserver
  1168.  * query, and any response is filtered out when processing the answer.
  1169.  * In listmode, the querytype is used to filter out the proper records.
  1170.  */
  1171.     /* set querytype for regular mode if unspecified */
  1172.     if ((querytype == T_NONE) && !listmode)
  1173.     {
  1174.         if ((queryaddr != NOT_DOTTED_QUAD) || reverse)
  1175.             querytype = T_PTR;
  1176.         else
  1177.             querytype = T_A;
  1178.     }
  1179.  
  1180. /*
  1181.  * Check for incompatible options.
  1182.  */
  1183.     /* cannot have dotted quad in listmode */
  1184.     if (listmode && (queryaddr != NOT_DOTTED_QUAD))
  1185.     {
  1186.         errmsg("Invalid query name %s", queryname);
  1187.         return(EX_USAGE);
  1188.     }
  1189.  
  1190.     /* must have regular name or dotted quad in addrmode */
  1191.     if (!listmode && addrmode && reverse)
  1192.     {
  1193.         errmsg("Invalid query name %s", queryname);
  1194.         return(EX_USAGE);
  1195.     }
  1196.  
  1197.     /* show what we are going to query about */
  1198.     if (verbose)
  1199.         show_types(queryname, querytype, queryclass);
  1200.  
  1201. /*
  1202.  * All set. Perform requested function.
  1203.  */
  1204.     result = execute(queryname, queryaddr);
  1205.     return(result ? EX_SUCCESS : EX_UNAVAILABLE);
  1206. }
  1207.  
  1208. /*
  1209. ** EXECUTE -- Perform the requested function
  1210. ** -----------------------------------------
  1211. **
  1212. **    Returns:
  1213. **        TRUE if information was obtained successfully.
  1214. **        FALSE otherwise.
  1215. **
  1216. **    The whole environment has been set up and checked.
  1217. */
  1218.  
  1219. bool
  1220. execute(name, addr)
  1221. input char *name;            /* name to query about */
  1222. input ipaddr_t addr;            /* explicit address of query */
  1223. {
  1224.     bool result;            /* result status of action taken */
  1225.  
  1226. /*
  1227.  * Special mode to list contents of specified zone.
  1228.  */
  1229.     if (listmode)
  1230.     {
  1231.         result = list_zone(name);
  1232.         return(result);
  1233.     }
  1234.  
  1235. /*
  1236.  * Special mode to check reverse mappings of host addresses.
  1237.  */
  1238.     if (addrmode)
  1239.     {
  1240.         if (addr == NOT_DOTTED_QUAD)
  1241.             result = check_addr(name);
  1242.         else
  1243.             result = check_name(addr);
  1244.         return(result);
  1245.     }
  1246.  
  1247. /*
  1248.  * Regular mode to query about specified host.
  1249.  */
  1250.     result = host_query(name, addr);
  1251.     return(result);
  1252. }
  1253.  
  1254. /*
  1255. ** HOST_QUERY -- Regular mode to query about specified host
  1256. ** --------------------------------------------------------
  1257. **
  1258. **    Returns:
  1259. **        TRUE if information was obtained successfully.
  1260. **        FALSE otherwise.
  1261. */
  1262.  
  1263. bool
  1264. host_query(name, addr)
  1265. input char *name;            /* name to query about */
  1266. input ipaddr_t addr;            /* explicit address of query */
  1267. {
  1268.     struct hostent *hp;
  1269.     struct in_addr inaddr;
  1270.     char newnamebuf[MAXDNAME+1];
  1271.     char *newname = NULL;        /* name to which CNAME is aliased */
  1272.     int ncnames = 0;        /* count of CNAMEs in chain */
  1273.     bool result;            /* result status of action taken */
  1274.  
  1275.     inaddr.s_addr = addr;
  1276.  
  1277.     result = FALSE;
  1278.     h_errno = TRY_AGAIN;
  1279.  
  1280.     /* retry until positive result or permanent failure */
  1281.     while (result == FALSE && h_errno == TRY_AGAIN)
  1282.     {
  1283.         /* reset before each query to avoid stale data */
  1284.         errno = 0;
  1285.         realname = NULL;
  1286.  
  1287.         if (addr == NOT_DOTTED_QUAD)
  1288.         {
  1289.             /* reset CNAME indicator */
  1290.             cname = NULL;
  1291.  
  1292.             /* lookup the name in question */
  1293.             if (newname == NULL)
  1294.                 result = get_hostinfo(name, FALSE);
  1295.             else
  1296.                 result = get_hostinfo(newname, TRUE);
  1297.  
  1298.             /* recurse on CNAMEs, but not too deep */
  1299.             if (cname && (querytype != T_CNAME))
  1300.             {
  1301.                 newname = strcpy(newnamebuf, cname);
  1302.  
  1303.                 if (ncnames++ > MAXCHAIN)
  1304.                 {
  1305.                     errmsg("Possible CNAME loop");
  1306.                     return(FALSE);
  1307.                 }
  1308.  
  1309.                 result = FALSE;
  1310.                 h_errno = TRY_AGAIN;
  1311.                 continue;
  1312.             }
  1313.         }
  1314.         else
  1315.         {
  1316.             hp = geth_byaddr((char *)&inaddr, INADDRSZ, AF_INET);
  1317.             if (hp != NULL)
  1318.             {
  1319.                 print_host("Name", hp);
  1320.                 result = TRUE;
  1321.             }
  1322.         }
  1323.  
  1324.         /* only retry if so requested */
  1325.         if (!waitmode)
  1326.             break;
  1327.     }
  1328.  
  1329.     /* use actual name if available */
  1330.     if (realname != NULL)
  1331.         name = realname;
  1332.  
  1333.     /* explain the reason of a failure */
  1334.     if (result == FALSE)
  1335.         ns_error(name, querytype, queryclass, server);
  1336.  
  1337.     return(result);
  1338. }
  1339.  
  1340. /*
  1341. ** MYHOSTNAME -- Determine our own fully qualified host name
  1342. ** ---------------------------------------------------------
  1343. **
  1344. **    Returns:
  1345. **        Pointer to own host name.
  1346. **        Aborts if host name could not be determined.
  1347. */
  1348.  
  1349. char *
  1350. myhostname()
  1351. {
  1352.     struct hostent *hp;
  1353.     static char mynamebuf[MAXDNAME+1];
  1354.     static char *myname = NULL;
  1355.  
  1356.     if (myname == NULL)
  1357.     {
  1358.         if (gethostname(mynamebuf, MAXDNAME) < 0)
  1359.         {
  1360.             perror("gethostname");
  1361.             exit(EX_OSERR);
  1362.         }
  1363.         mynamebuf[MAXDNAME] = '\0';
  1364.  
  1365.         hp = gethostbyname(mynamebuf);
  1366.         if (hp == NULL)
  1367.         {
  1368.             ns_error(mynamebuf, T_A, C_IN, server);
  1369.             errmsg("Error in looking up own name");
  1370.             exit(EX_NOHOST);
  1371.         }
  1372.  
  1373.         /* cache the result */
  1374.         myname = strncpy(mynamebuf, hp->h_name, MAXDNAME);
  1375.         myname[MAXDNAME] = '\0';
  1376.     }
  1377.  
  1378.     return(myname);
  1379. }
  1380.  
  1381. /*
  1382. ** SET_SERVER -- Override default nameserver with explicit server
  1383. ** --------------------------------------------------------------
  1384. **
  1385. **    Returns:
  1386. **        None.
  1387. **        Aborts the program if an unknown host was given.
  1388. **
  1389. **    Side effects:
  1390. **        The global variable ``server'' is set to indicate
  1391. **        that an explicit server is being used.
  1392. **
  1393. **    The default nameserver addresses in the resolver database
  1394. **    which are initialized by res_init() from /etc/resolv.conf
  1395. **    are replaced with the (possibly multiple) addresses of an
  1396. **    explicitly named server host. If a dotted quad is given,
  1397. **    only that single address will be used.
  1398. **
  1399. **    The answers from such server must be interpreted with some
  1400. **    care if we don't know beforehand whether it can be trusted.
  1401. */
  1402.  
  1403. void
  1404. set_server(name)
  1405. input char *name;            /* name of server to be queried */
  1406. {
  1407.     register int i;
  1408.     struct hostent *hp;
  1409.     struct in_addr inaddr;
  1410.     ipaddr_t addr;            /* explicit address of server */
  1411.  
  1412.     /* check for nonsense input name */
  1413.     if (strlength(name) > MAXDNAME)
  1414.     {
  1415.         errmsg("Server name %s too long", name);
  1416.         exit(EX_USAGE);
  1417.     }
  1418.  
  1419. /*
  1420.  * Overrule the default nameserver addresses.
  1421.  */
  1422.     addr = inet_addr(name);
  1423.     inaddr.s_addr = addr;
  1424.  
  1425.     if (addr == NOT_DOTTED_QUAD)
  1426.     {
  1427.         /* lookup all of its addresses; this must not fail */
  1428.         hp = gethostbyname(name);
  1429.         if (hp == NULL)
  1430.         {
  1431.             ns_error(name, T_A, C_IN, server);
  1432.             errmsg("Error in looking up server name");
  1433.             exit(EX_NOHOST);
  1434.         }
  1435.  
  1436.         for (i = 0; i < MAXNS && hp->h_addr_list[i]; i++)
  1437.         {
  1438.             nslist(i).sin_family = AF_INET;
  1439.             nslist(i).sin_port = htons(NAMESERVER_PORT);
  1440.             nslist(i).sin_addr = incopy(hp->h_addr_list[i]);
  1441.         }
  1442.         _res.nscount = i;
  1443.     }
  1444.     else
  1445.     {
  1446.         /* lookup the name, but use only the given address */
  1447.         hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
  1448.  
  1449.         nslist(0).sin_family = AF_INET;
  1450.         nslist(0).sin_port = htons(NAMESERVER_PORT);
  1451.         nslist(0).sin_addr = inaddr;
  1452.         _res.nscount = 1;
  1453.     }
  1454.  
  1455. /*
  1456.  * Indicate the use of an explicit server.
  1457.  */
  1458.     if (hp != NULL)
  1459.     {
  1460.         server = strncpy(serverbuf, hp->h_name, MAXDNAME);
  1461.         server[MAXDNAME] = '\0';
  1462.  
  1463.         if (verbose)
  1464.             print_host("Server", hp);
  1465.     }
  1466.     else
  1467.     {
  1468.         server = strcpy(serverbuf, inet_ntoa(inaddr));
  1469.  
  1470.         if (verbose)
  1471.             printf("Server: %s\n\n", server);
  1472.     }
  1473. }
  1474.  
  1475. /*
  1476. ** SET_LOGFILE -- Initialize optional log file
  1477. ** -------------------------------------------
  1478. **
  1479. **    Returns:
  1480. **        None.
  1481. **        Aborts the program if the file could not be created.
  1482. **
  1483. **    Side effects:
  1484. **        The global variable ``logfile'' is set to indicate
  1485. **        that resource record output is to be written to it.
  1486. **
  1487. **    Swap ordinary stdout and log file output if so requested.
  1488. */
  1489.  
  1490. void
  1491. set_logfile(filename)
  1492. input char *filename;            /* name of log file */
  1493. {
  1494.     if (logexchange)
  1495.     {
  1496.         logfile = fdopen(dup(STDOUT), "w");
  1497.         if (logfile == NULL)
  1498.         {
  1499.             perror("fdopen");
  1500.             exit(EX_OSERR);
  1501.         }
  1502.  
  1503.         if (freopen(filename, "w", stdout) == NULL)
  1504.         {
  1505.             perror(filename);
  1506.             exit(EX_CANTCREAT);
  1507.         }
  1508.     }
  1509.     else
  1510.     {
  1511.         logfile = fopen(filename, "w");
  1512.         if (logfile == NULL)
  1513.         {
  1514.             perror(filename);
  1515.             exit(EX_CANTCREAT);
  1516.         }
  1517.     }
  1518. }
  1519.  
  1520. /*
  1521. ** FATAL -- Abort program when illegal option encountered
  1522. ** ------------------------------------------------------
  1523. **
  1524. **    Returns:
  1525. **        Aborts after issuing error message.
  1526. */
  1527.  
  1528. void /*VARARGS1*/
  1529. fatal(fmt, a, b, c, d)
  1530. input char *fmt;            /* format of message */
  1531. input char *a, *b, *c, *d;        /* optional arguments */
  1532. {
  1533.     (void) fprintf(stderr, fmt, a, b, c, d);
  1534.     (void) fprintf(stderr, "\n");
  1535.     exit(EX_USAGE);
  1536. }
  1537.  
  1538.  
  1539. /*
  1540. ** ERRMSG -- Issue error message to error output
  1541. ** ---------------------------------------------
  1542. **
  1543. **    Returns:
  1544. **        None.
  1545. **
  1546. **    Side effects:
  1547. **        Increments the global error count.
  1548. */
  1549.  
  1550. void /*VARARGS1*/
  1551. errmsg(fmt, a, b, c, d)
  1552. input char *fmt;            /* format of message */
  1553. input char *a, *b, *c, *d;        /* optional arguments */
  1554. {
  1555.     (void) fprintf(stderr, fmt, a, b, c, d);
  1556.     (void) fprintf(stderr, "\n");
  1557.  
  1558.     /* flag an error */
  1559.     errorcount++;
  1560. }
  1561.  
  1562. /*
  1563. ** GET_HOSTINFO -- Principal routine to query about given name
  1564. ** -----------------------------------------------------------
  1565. **
  1566. **    Returns:
  1567. **        TRUE if requested info was obtained successfully.
  1568. **        FALSE otherwise.
  1569. **
  1570. **    This is the equivalent of the resolver module res_search().
  1571. **
  1572. **    In this program RES_DEFNAMES is always on, and RES_DNSRCH
  1573. **    is off by default. This means that single names without dot
  1574. **    are always, and only, tried within the own default domain,
  1575. **    and compound names are assumed to be already fully qualified.
  1576. **
  1577. **    The default BIND behavior can be simulated by turning on
  1578. **    RES_DNSRCH with -R. The given name, whether or not compound,
  1579. **    is then    first tried within the possible search domains.
  1580. **
  1581. **    Note. In the latter case, the search terminates in case the
  1582. **    specified name exists but does not have the desired type.
  1583. **    The BIND behavior is to continue the search. This can be
  1584. **    simulated with the undocumented option -B.
  1585. */
  1586.  
  1587. bool
  1588. get_hostinfo(name, qualified)
  1589. input char *name;            /* name to query about */
  1590. input bool qualified;            /* assume fully qualified if set */
  1591. {
  1592.     register char **domain;
  1593.     register char *cp;
  1594.     int dot;            /* number of dots in query name */
  1595.     bool result;            /* result status of action taken */
  1596.     char oldnamebuf[2*MAXDNAME+2];
  1597.     char *oldname;            /* saved actual name when NO_DATA */
  1598.     int nodata = 0;            /* NO_DATA status during DNSRCH */
  1599.     int nquery = 0;            /* number of extra search queries */
  1600.  
  1601. /*
  1602.  * Single dot means root zone.
  1603.  */
  1604.     if (sameword(name, "."))
  1605.         qualified = TRUE;
  1606.  
  1607. /*
  1608.  * Names known to be fully qualified are just tried ``as is''.
  1609.  */
  1610.     if (qualified)
  1611.     {
  1612.         result = get_domaininfo(name, (char *)NULL);
  1613.         return(result);
  1614.     }
  1615.  
  1616. /*
  1617.  * Count number of dots. Move to the end of the name.
  1618.  */
  1619.     for (dot = 0, cp = name; *cp != '\0'; cp++)
  1620.         if (*cp == '.')
  1621.             dot++;
  1622.  
  1623. /*
  1624.  * Check for aliases of single name.
  1625.  * Note that the alias is supposed to be fully qualified.
  1626.  */
  1627.     if (dot == 0 && (cp = hostalias(name)) != NULL)
  1628.     {
  1629.         if (verbose)
  1630.             printf("Aliased %s to %s\n", name, cp);
  1631.  
  1632.         result = get_domaininfo(cp, (char *)NULL);
  1633.         return(result);
  1634.     }
  1635.  
  1636. /*
  1637.  * Trailing dot means absolute (fully qualified) address.
  1638.  */
  1639.     if (dot != 0 && cp[-1] == '.')
  1640.     {
  1641.         cp[-1] = '\0';
  1642.         result = get_domaininfo(name, (char *)NULL);
  1643.         cp[-1] = '.';
  1644.         return(result);
  1645.     }
  1646.  
  1647. /*
  1648.  * Append own default domain and other search domains if appropriate.
  1649.  */
  1650.     if ((dot == 0 && bitset(RES_DEFNAMES, _res.options)) ||
  1651.         (dot != 0 && bitset(RES_DNSRCH, _res.options)))
  1652.     {
  1653.         for (domain = _res.dnsrch; *domain; domain++)
  1654.         {
  1655.             result = get_domaininfo(name, *domain);
  1656.             if (result)
  1657.                 return(result);
  1658.  
  1659.             /* keep count of extra search queries */
  1660.             nquery++;
  1661.  
  1662.             /* in case nameserver not present */
  1663.             if (errno == ECONNREFUSED)
  1664.                 return(FALSE);
  1665.  
  1666.             /* if no further search desired (single name) */
  1667.                 if (!bitset(RES_DNSRCH, _res.options))
  1668.                 break;
  1669.  
  1670.             /* if name exists but has not requested type */
  1671.             if (h_errno == NO_DATA || h_errno == NO_RREC)
  1672.             {
  1673.                 if (bindcompat)
  1674.                 {
  1675.                     /* remember status and search up */
  1676.                     oldname = strcpy(oldnamebuf, realname);
  1677.                     nodata = h_errno;
  1678.                     continue;
  1679.                 }
  1680.  
  1681.                 return(FALSE);
  1682.             }
  1683.  
  1684.             /* retry only if name does not exist at all */
  1685.             if (h_errno != HOST_NOT_FOUND && h_errno != NO_HOST)
  1686.                 break;
  1687.         }
  1688.     }
  1689.  
  1690. /*
  1691.  * Single name lookup failed.
  1692.  */
  1693.     if (dot == 0)
  1694.     {
  1695.         /* unclear what actual name should be */
  1696.         if (nquery != 1)
  1697.             realname = NULL;
  1698.  
  1699.         /* restore nodata status from search */
  1700.         if (bindcompat && nodata)
  1701.         {
  1702.             realname = strcpy(realnamebuf, oldname);
  1703.             h_errno = nodata;
  1704.         }
  1705.  
  1706.         /* set status in case we never queried */
  1707.         if (!bitset(RES_DEFNAMES, _res.options))
  1708.             h_errno = HOST_NOT_FOUND;
  1709.  
  1710.         return(FALSE);
  1711.     }
  1712.  
  1713. /*
  1714.  * Rest means fully qualified.
  1715.  */
  1716.     result = get_domaininfo(name, (char *)NULL);
  1717.  
  1718.     /* restore nodata status from search */
  1719.     if (!result && bindcompat && nodata)
  1720.     {
  1721.         realname = strcpy(realnamebuf, oldname);
  1722.         h_errno = nodata;
  1723.     }
  1724.  
  1725.     return(result);
  1726. }
  1727.  
  1728. /*
  1729. ** GET_DOMAININFO -- Fetch and print desired info about name in domain
  1730. ** -------------------------------------------------------------------
  1731. **
  1732. **    Returns:
  1733. **        TRUE if requested info was obtained successfully.
  1734. **        FALSE otherwise.
  1735. **
  1736. **    Side effects:
  1737. **        Sets global variable ``realname'' to actual name queried.
  1738. **
  1739. **    This is the equivalent of the resolver module res_querydomain().
  1740. **
  1741. **    Things get a little complicated in case RES_DNSRCH is on.
  1742. **    If we get an answer but the data is corrupted, an error will be
  1743. **    returned and NO_RECOVERY will be set. This will terminate the
  1744. **    extra search loop, but a compound name will still be tried as-is.
  1745. **    The same holds if the query times out or we have a server failure,
  1746. **    in which case an error will be returned and TRY_AGAIN will be set.
  1747. **    For now we take this for granted. Normally RES_DNSRCH is disabled.
  1748. **    In this default case we do only one query and we have no problem.
  1749. */
  1750.  
  1751. bool
  1752. get_domaininfo(name, domain)
  1753. input char *name;            /* name to query about */
  1754. input char *domain;            /* domain to which name is relative */
  1755. {
  1756.     char namebuf[2*MAXDNAME+2];    /* buffer to store full domain name */
  1757.     querybuf answer;
  1758.     register int n;
  1759.     bool result;            /* result status of action taken */
  1760.  
  1761. /*
  1762.  * Show what we are about to query.
  1763.  */
  1764.     if (verbose)
  1765.     {
  1766.         if (domain == NULL || domain[0] == '\0')
  1767.             printf("Trying %s", name);
  1768.         else
  1769.             printf("Trying %s within %s", name, domain);
  1770.  
  1771.         if (server && (verbose > 1))
  1772.             printf(" at server %s", server);
  1773.  
  1774.         printf(" ...\n");
  1775.     }
  1776.  
  1777. /*
  1778.  * Construct the actual domain name.
  1779.  * A null domain means the given name is already fully qualified.
  1780.  * If the composite name is too long, res_mkquery() will fail.
  1781.  */
  1782.     if (domain == NULL || domain[0] == '\0')
  1783.         (void) sprintf(namebuf, "%.*s", MAXDNAME, name);
  1784.     else
  1785.         (void) sprintf(namebuf, "%.*s.%.*s",
  1786.                 MAXDNAME, name, MAXDNAME, domain);
  1787.     name = namebuf;
  1788.  
  1789. /*
  1790.  * Fetch the desired info.
  1791.  */
  1792.     n = get_info(&answer, name, querytype, queryclass);
  1793.     result = (n < 0) ? FALSE : TRUE;
  1794.  
  1795. /*
  1796.  * Print the relevant data.
  1797.  * If we got a positive answer, the data may still be corrupted.
  1798.  */
  1799.     if (result)
  1800.         result = print_info(&answer, n, name, querytype, queryclass, TRUE);
  1801.  
  1802. /*
  1803.  * Remember the actual name that was queried.
  1804.  * Must be at the end to avoid clobbering during recursive calls.
  1805.  */
  1806.     realname = strcpy(realnamebuf, name);
  1807.  
  1808.     return(result);
  1809. }
  1810.  
  1811. /*
  1812. ** GET_INFO -- Basic routine to issue a nameserver query
  1813. ** -----------------------------------------------------
  1814. **
  1815. **    Returns:
  1816. **        Length of nameserver answer buffer, if obtained.
  1817. **        -1 if an error occurred (h_errno is set appropriately).
  1818. **
  1819. **    This is the equivalent of the resolver module res_query().
  1820. */
  1821.  
  1822. int
  1823. get_info(answerbuf, name, type, class)
  1824. output querybuf *answerbuf;        /* location of buffer to store answer */
  1825. input char *name;            /* full name to query about */
  1826. input int type;                /* specific resource record type */
  1827. input int class;            /* specific resource record class */
  1828. {
  1829.     querybuf query;
  1830.     HEADER *bp;
  1831.     int ancount;
  1832.     register int n;
  1833.  
  1834. /*
  1835.  * Construct query, and send it to the nameserver.
  1836.  * res_send() will fail if no nameserver responded. In the BIND version the
  1837.  * possible values for errno are ECONNREFUSED and ETIMEDOUT. If we did get
  1838.  * an answer, errno should be reset, since res_send() may have left an errno
  1839.  * in case it has used datagrams. Our private version of res_send() will leave
  1840.  * also other error statuses, and will clear errno if an answer was obtained.
  1841.  */
  1842.     errno = 0;    /* reset before querying nameserver */
  1843.  
  1844.     n = res_mkquery(QUERY, name, class, type, (qbuf_t *)NULL, 0,
  1845.             (rrec_t *)NULL, (qbuf_t *)&query, sizeof(querybuf));
  1846.     if (n < 0)
  1847.     {
  1848.         if (debug)
  1849.             printf("%sres_mkquery failed\n", dbprefix);
  1850.         h_errno = NO_RECOVERY;
  1851.         return(-1);
  1852.     }
  1853.  
  1854.     n = res_send((qbuf_t *)&query, n, (qbuf_t *)answerbuf, sizeof(querybuf));
  1855.     if (n < 0)
  1856.     {
  1857.         if (debug)
  1858.             printf("%sres_send failed\n", dbprefix);
  1859.         h_errno = TRY_AGAIN;
  1860.         return(-1);
  1861.     }
  1862.  
  1863.     errno = 0;    /* reset after we got an answer */
  1864.  
  1865.     if (n < HFIXEDSZ)
  1866.     {
  1867.         pr_error("answer length %s too short after %s query for %s",
  1868.             itoa(n), pr_type(type), name);
  1869.         h_errno = NO_RECOVERY;
  1870.         return(-1);
  1871.     }
  1872.  
  1873. /*
  1874.  * Analyze the status of the answer from the nameserver.
  1875.  */
  1876.     if ((verbose > print_level) || debug)
  1877.         print_status(answerbuf, n);
  1878.  
  1879.     bp = (HEADER *)answerbuf;
  1880.     ancount = ntohs(bp->ancount);
  1881.  
  1882.     if (bp->rcode != NOERROR || ancount == 0)
  1883.     {
  1884.         switch (bp->rcode)
  1885.         {
  1886.             case NXDOMAIN:
  1887.             /* distinguish between authoritative or not */
  1888.             h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
  1889.             break;
  1890.  
  1891.             case NOERROR:
  1892.             /* distinguish between authoritative or not */
  1893.             h_errno = bp->aa ? NO_DATA : NO_RREC;
  1894.             break;
  1895.  
  1896.             case SERVFAIL:
  1897.             h_errno = SERVER_FAILURE; /* instead of TRY_AGAIN */
  1898.             break;
  1899.  
  1900.             case REFUSED:
  1901.             h_errno = QUERY_REFUSED; /* instead of NO_RECOVERY */
  1902.             break;
  1903.  
  1904.             default:
  1905.             h_errno = NO_RECOVERY; /* FORMERR NOTIMP NOCHANGE */
  1906.             break;
  1907.         }
  1908.         return(-1);
  1909.     }
  1910.  
  1911.     /* valid answer received, avoid buffer overrun */
  1912.     h_errno = 0;
  1913.     return(querysize(n));
  1914. }
  1915.  
  1916. /*
  1917. ** PRINT_INFO -- Check resource records in answer and print relevant data
  1918. ** ----------------------------------------------------------------------
  1919. **
  1920. **    Returns:
  1921. **        TRUE if answer buffer was processed successfully.
  1922. **        FALSE otherwise.
  1923. **
  1924. **    Side effects:
  1925. **        Will recurse on MAILB records if appropriate.
  1926. **        See also side effects of the print_rrec() routine.
  1927. */
  1928.  
  1929. bool
  1930. print_info(answerbuf, answerlen, name, type, class, regular)
  1931. input querybuf *answerbuf;        /* location of answer buffer */
  1932. input int answerlen;            /* length of answer buffer */
  1933. input char *name;            /* full name we are querying about */
  1934. input int type;                /* record type we are querying about */
  1935. input int class;            /* record class we are querying about */
  1936. input bool regular;            /* set if this is a regular lookup */
  1937. {
  1938.     HEADER *bp;
  1939.     int qdcount, ancount, nscount, arcount;
  1940.     u_char *msg, *eom;
  1941.     register u_char *cp;
  1942.  
  1943.     bp = (HEADER *)answerbuf;
  1944.     qdcount = ntohs(bp->qdcount);
  1945.     ancount = ntohs(bp->ancount);
  1946.     nscount = ntohs(bp->nscount);
  1947.     arcount = ntohs(bp->arcount);
  1948.  
  1949.     msg = (u_char *)answerbuf;
  1950.     eom = (u_char *)answerbuf + answerlen;
  1951.     cp  = (u_char *)answerbuf + HFIXEDSZ;
  1952.  
  1953. /*
  1954.  * Skip the query section in the response (present only in normal queries).
  1955.  */
  1956.     if (qdcount)
  1957.     {
  1958.         while (qdcount > 0 && cp < eom)    /* process all records */
  1959.         {
  1960.             cp = skip_qrec(name, type, class, cp, msg, eom);
  1961.             if (cp == NULL)
  1962.                 return(FALSE);
  1963.             qdcount--;
  1964.         }
  1965.  
  1966.         if (qdcount)
  1967.         {
  1968.             pr_error("invalid qdcount after %s query for %s",
  1969.                 pr_type(type), name);
  1970.             h_errno = NO_RECOVERY;
  1971.             return(FALSE);
  1972.         }
  1973.     }
  1974.  
  1975. /*
  1976.  * Process the actual answer section in the response.
  1977.  * During zone transfers, this is the only section available.
  1978.  */
  1979.     if (ancount)
  1980.     {
  1981.         if ((type != T_AXFR) && verbose && !bp->aa)
  1982.             printf("The following answer is not authoritative:\n");
  1983.  
  1984.         while (ancount > 0 && cp < eom)
  1985.         {
  1986.             /* reset for each record during zone listings */
  1987.             soaname = NULL, subname = NULL, adrname = NULL, address = 0;
  1988.  
  1989.             print_level++;
  1990.             cp = print_rrec(name, type, class, cp, msg, eom, regular);
  1991.             print_level--;
  1992.             if (cp == NULL)
  1993.                 return(FALSE);
  1994.             ancount--;
  1995.  
  1996.             /* update zone information during zone listings */
  1997.             if (type == T_AXFR)
  1998.                 update_zone(name);
  1999.  
  2000.             /* we trace down CNAME chains ourselves */
  2001.             if (regular && !verbose && cname)
  2002.                 return(TRUE);
  2003.  
  2004.             /* recursively expand MR/MG records into MB records */
  2005.             if (regular && mailmode && mname)
  2006.                 (void) get_recursive(&mname);
  2007.         }
  2008.  
  2009.         if (ancount)
  2010.         {
  2011.             pr_error("invalid ancount after %s query for %s",
  2012.                 pr_type(type), name);
  2013.             h_errno = NO_RECOVERY;
  2014.             return(FALSE);
  2015.         }
  2016.     }
  2017.  
  2018. /*
  2019.  * The nameserver and additional info section are normally not processed.
  2020.  * Both sections shouldn't exist in zone transfers.
  2021.  */
  2022.     if (!verbose || exclusive)
  2023.         return(TRUE);
  2024.  
  2025.     if (nscount)
  2026.     {
  2027.         printf("Authoritative nameservers:\n");
  2028.  
  2029.         while (nscount > 0 && cp < eom)
  2030.         {
  2031.             print_level++;
  2032.             cp = print_rrec(name, type, class, cp, msg, eom, FALSE);
  2033.             print_level--;
  2034.             if (cp == NULL)
  2035.                 return(FALSE);
  2036.             nscount--;
  2037.         }
  2038.  
  2039.         if (nscount)
  2040.         {
  2041.             pr_error("invalid nscount after %s query for %s",
  2042.                 pr_type(type), name);
  2043.             h_errno = NO_RECOVERY;
  2044.             return(FALSE);
  2045.         }
  2046.     }
  2047.  
  2048.     if (arcount)
  2049.     {
  2050.         printf("Additional information:\n");
  2051.  
  2052.         while (arcount > 0 && cp < eom)
  2053.         {
  2054.             print_level++;
  2055.             cp = print_rrec(name, type, class, cp, msg, eom, FALSE);
  2056.             print_level--;
  2057.             if (cp == NULL)
  2058.                 return(FALSE);
  2059.             arcount--;
  2060.         }
  2061.  
  2062.         if (arcount)
  2063.         {
  2064.             pr_error("invalid arcount after %s query for %s",
  2065.                 pr_type(type), name);
  2066.             h_errno = NO_RECOVERY;
  2067.             return(FALSE);
  2068.         }
  2069.     }
  2070.  
  2071.     /* all sections were processed successfully */
  2072.     return(TRUE);
  2073. }
  2074.  
  2075. /*
  2076. ** PRINT_DATA -- Output resource record data if this record is wanted
  2077. ** ------------------------------------------------------------------
  2078. **
  2079. **    Returns:
  2080. **        None.
  2081. **
  2082. **    Inputs:
  2083. **        The global variable ``doprint'' is set by print_rrec()
  2084. **        if we need to print the data.
  2085. */
  2086.  
  2087. static bool doprint;        /* indicates whether or not to print */
  2088.  
  2089. void /*VARARGS1*/
  2090. print_data(fmt, a, b, c, d)
  2091. input char *fmt;            /* format of message */
  2092. input char *a, *b, *c, *d;        /* optional arguments */
  2093. {
  2094.     /* if (doprint) */
  2095.     {
  2096.         if (!suppress)
  2097.             printf(fmt, a, b, c, d);
  2098.  
  2099.         if (logfile != NULL)
  2100.             (void) fprintf(logfile, fmt, a, b, c, d);
  2101.     }
  2102. }
  2103.  
  2104. #define doprintf(x)\
  2105. {\
  2106.     if (doprint)\
  2107.     {\
  2108.         print_data x ;\
  2109.     }\
  2110. }
  2111.  
  2112. /*
  2113. ** PRINT_RREC -- Decode single resource record and output relevant data
  2114. ** --------------------------------------------------------------------
  2115. **
  2116. **    Returns:
  2117. **        Pointer to position in answer buffer after current record.
  2118. **        NULL if there was a format error in the current record.
  2119. **
  2120. **    Outputs:
  2121. **        The global variable ``doprint'' is set appropriately
  2122. **        for use by print_data().
  2123. **
  2124. **    Side effects:
  2125. **        Updates resource record statistics in record_stats[].
  2126. **        Sets ``soaname'' if this is an SOA record.
  2127. **        Sets ``subname'' if this is an NS record.
  2128. **        Sets ``adrname'' if this is an A record.
  2129. **        Sets ``address'' if this is an A record.
  2130. **        Sets ``cname'' if this is a valid CNAME record.
  2131. **        Sets ``mname'' if this is a valid MAILB record.
  2132. **        These variables must have been cleared before calling
  2133. **        print_info() and may be checked afterwards.
  2134. */
  2135.  
  2136. /* print domain names after certain conversions */
  2137. #define pr_name(x)    pr_domain(x, listing)
  2138.  
  2139. /* check the LHS record name of these records for invalid characters */
  2140. #define test_valid(t)    (((t == T_A) && !reverse) || t == T_MX || t == T_AAAA)
  2141.  
  2142. /* check the RHS domain name of these records for canonical host names */
  2143. #define test_canon(t)    (t == T_NS || t == T_MX)
  2144.  
  2145. u_char *
  2146. print_rrec(name, qtype, qclass, cp, msg, eom, regular)
  2147. input char *name;            /* full name we are querying about */
  2148. input int qtype;            /* record type we are querying about */
  2149. input int qclass;            /* record class we are querying about */
  2150. register u_char *cp;            /* current position in answer buf */
  2151. input u_char *msg, *eom;        /* begin and end of answer buf */
  2152. input bool regular;            /* set if this is a regular lookup */
  2153. {
  2154.     char rname[MAXDNAME+1];        /* record name in LHS */
  2155.     char dname[MAXDNAME+1];        /* domain name in RHS */
  2156.     int type, class, ttl, dlen;    /* fixed values in every record */
  2157.     u_char *eor;            /* predicted position of next record */
  2158.     bool classmatch;        /* set if we want to see this class */
  2159.     bool listing;            /* set if this is a zone listing */
  2160.     char *host = listhost;        /* contacted host for zone listings */
  2161.     register int n, c;
  2162.     struct in_addr inaddr;
  2163.     struct protoent *protocol;
  2164.     struct servent *service;
  2165.  
  2166. /*
  2167.  * Pickup the standard values present in each resource record.
  2168.  */
  2169.     n = expand_name(name, T_NONE, cp, msg, eom, rname);
  2170.     if (n < 0)
  2171.         return(NULL);
  2172.     cp += n;
  2173.  
  2174.     n = 3*INT16SZ + INT32SZ;
  2175.     if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  2176.         return(NULL);
  2177.  
  2178.     type = _getshort(cp);
  2179.     cp += INT16SZ;
  2180.  
  2181.     class = _getshort(cp);
  2182.     cp += INT16SZ;
  2183.  
  2184.     ttl = _getlong(cp);
  2185.     cp += INT32SZ;
  2186.  
  2187.     dlen = _getshort(cp);
  2188.     cp += INT16SZ;
  2189.  
  2190.     eor = cp + dlen;
  2191.  
  2192. /*
  2193.  * Decide whether or not to print this resource record.
  2194.  */
  2195.     listing = (qtype == T_AXFR || qtype == T_IXFR) ? TRUE : FALSE;
  2196.  
  2197.     if (listing)
  2198.     {
  2199.         classmatch = want_class(class, queryclass);
  2200.         doprint = classmatch && want_type(type, querytype);
  2201.     }
  2202.     else
  2203.     {
  2204.         classmatch = want_class(class, C_ANY);
  2205.         doprint = classmatch && want_type(type, T_ANY);
  2206.     }
  2207.  
  2208.     if (doprint && exclusive && !indomain(rname, name, TRUE))
  2209.         doprint = FALSE;
  2210.  
  2211.     if (doprint && exclusive && fakename(rname))
  2212.         doprint = FALSE;
  2213.  
  2214.     if (doprint && wildcards && !in_string(rname, '*'))
  2215.         doprint = FALSE;
  2216. #ifdef justfun
  2217.     if (namelen && (strlength(rname) < namelen))
  2218.         doprint = FALSE;
  2219. #endif
  2220.  
  2221. /*
  2222.  * Print name and common values, if appropriate.
  2223.  */
  2224.     doprintf(("%-20s", pr_name(rname)))
  2225.  
  2226.     if (verbose || ttlprint)
  2227.         doprintf(("\t%s", itoa(ttl)))
  2228.  
  2229.     if (verbose || classprint || (class != qclass))
  2230.         doprintf(("\t%s", pr_class(class)))
  2231.  
  2232.     doprintf(("\t%s", pr_type(type)))
  2233.  
  2234. /*
  2235.  * Update resource record statistics for zone listing.
  2236.  */
  2237.     if (listing && classmatch)
  2238.     {
  2239.         if (type >= T_FIRST && type <= T_LAST)
  2240.             record_stats[type]++;
  2241.     }
  2242.  
  2243. /*
  2244.  * Save the domain name of an SOA or NS or A record for zone listing.
  2245.  */
  2246.     if (listing && classmatch)
  2247.     {
  2248.         if (type == T_A)
  2249.             adrname = strcpy(adrnamebuf, rname);
  2250.  
  2251.         else if (type == T_NS)
  2252.             subname = strcpy(subnamebuf, rname);
  2253.  
  2254.         else if (type == T_SOA)
  2255.             soaname = strcpy(soanamebuf, rname);
  2256.     }
  2257.  
  2258. /*
  2259.  * Print type specific data, if appropriate.
  2260.  */
  2261.     switch (type)
  2262.     {
  2263.         case T_A:
  2264.         if (class == C_IN || class == C_HS)
  2265.         {
  2266.             if (dlen == INADDRSZ)
  2267.             {
  2268.                 bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  2269.                 address = inaddr.s_addr;
  2270.                 doprintf(("\t%s", inet_ntoa(inaddr)))
  2271.                 cp += INADDRSZ;
  2272.                 break;
  2273.             }
  2274. #ifdef obsolete
  2275.             if (dlen == INADDRSZ + 1 + INT16SZ)
  2276.             {
  2277.                 bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  2278.                 address = inaddr.s_addr;
  2279.                 doprintf(("\t%s", inet_ntoa(inaddr)))
  2280.                 cp += INADDRSZ;
  2281.  
  2282.                 n = *cp++;
  2283.                 doprintf((" ; proto = %s", itoa(n)))
  2284.  
  2285.                 n = _getshort(cp);
  2286.                 doprintf((", port = %s", itoa(n)))
  2287.                 cp += INT16SZ;
  2288.                 break;
  2289.             }
  2290. #endif
  2291.             address = 0;
  2292.             break;
  2293.         }
  2294.         address = 0;
  2295.         cp += dlen;
  2296.         break;
  2297.  
  2298.         case T_MX:
  2299.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2300.             break;
  2301.         n = _getshort(cp);
  2302.         doprintf(("\t%s", itoa(n)))
  2303.         cp += INT16SZ;
  2304.  
  2305.         n = expand_name(rname, type, cp, msg, eom, dname);
  2306.         if (n < 0)
  2307.             break;
  2308.         doprintf((" %s", pr_name(dname)))
  2309.         cp += n;
  2310.         break;
  2311.  
  2312.         case T_NS:
  2313.         case T_PTR:
  2314.         case T_CNAME:
  2315.         n = expand_name(rname, type, cp, msg, eom, dname);
  2316.         if (n < 0)
  2317.             break;
  2318.         doprintf(("\t%s", pr_name(dname)))
  2319.         cp += n;
  2320.         break;
  2321.  
  2322.         case T_HINFO:
  2323.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2324.             break;
  2325.         n = *cp++;
  2326.         doprintf(("\t\"%s\"", stoa(cp, n, TRUE)))
  2327.         cp += n;
  2328.  
  2329.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2330.             break;
  2331.         n = *cp++;
  2332.         doprintf(("\t\"%s\"", stoa(cp, n, TRUE)))
  2333.         cp += n;
  2334.         break;
  2335.  
  2336.         case T_SOA:
  2337.         n = expand_name(rname, type, cp, msg, eom, dname);
  2338.         if (n < 0)
  2339.             break;
  2340.         doprintf(("\t%s", pr_name(dname)))
  2341.         cp += n;
  2342.  
  2343.         n = expand_name(rname, type, cp, msg, eom, dname);
  2344.         if (n < 0)
  2345.             break;
  2346.         doprintf((" %s", pr_name(dname)))
  2347.         cp += n;
  2348.  
  2349.         n = 5*INT32SZ;
  2350.         if (check_size(rname, type, cp, msg, eor, n) < 0)
  2351.             break;
  2352.         doprintf((" ("))
  2353.  
  2354.         n = _getlong(cp);
  2355.         doprintf(("\n\t\t\t%s", utoa(n)))
  2356.         doprintf(("\t;serial (version)"))
  2357.         cp += INT32SZ;
  2358.  
  2359.         n = _getlong(cp);
  2360.         doprintf(("\n\t\t\t%s", itoa(n)))
  2361.         doprintf(("\t;refresh period (%s)", pr_time(n, FALSE)))
  2362.         cp += INT32SZ;
  2363.  
  2364.         n = _getlong(cp);
  2365.         doprintf(("\n\t\t\t%s", itoa(n)))
  2366.         doprintf(("\t;retry interval (%s)", pr_time(n, FALSE)))
  2367.         cp += INT32SZ;
  2368.  
  2369.         n = _getlong(cp);
  2370.         doprintf(("\n\t\t\t%s", itoa(n)))
  2371.         doprintf(("\t;expire time (%s)", pr_time(n, FALSE)))
  2372.         cp += INT32SZ;
  2373.  
  2374.         n = _getlong(cp);
  2375.         doprintf(("\n\t\t\t%s", itoa(n)))
  2376.         doprintf(("\t;default ttl (%s)", pr_time(n, FALSE)))
  2377.         cp += INT32SZ;
  2378.  
  2379.         doprintf(("\n\t\t\t)"))
  2380.         break;
  2381.  
  2382.         case T_WKS:
  2383.         if (check_size(rname, type, cp, msg, eor, INADDRSZ) < 0)
  2384.             break;
  2385.         bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  2386.         doprintf(("\t%s", inet_ntoa(inaddr)))
  2387.         cp += INADDRSZ;
  2388.  
  2389.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2390.             break;
  2391.         n = *cp++;
  2392.  
  2393.         protocol = getprotobynumber(n);
  2394.         if (protocol != NULL)
  2395.             doprintf((" %s", protocol->p_name))
  2396.         else
  2397.             doprintf((" %s", itoa(n)))
  2398.  
  2399.         doprintf((" ("))
  2400.         n = 0;
  2401.         while (cp < eor)
  2402.         {
  2403.             c = *cp++;
  2404.             do
  2405.             {
  2406.              if (c & 0200)
  2407.             {
  2408.                 int port;
  2409.  
  2410.                 port = htons(n);
  2411.                 if (protocol != NULL)
  2412.                     service = getservbyport(port, protocol->p_name);
  2413.                 else
  2414.                     service = NULL;
  2415.  
  2416.                 if (service != NULL)
  2417.                     doprintf((" %s", service->s_name))
  2418.                 else
  2419.                     doprintf((" %s", itoa(n)))
  2420.             }
  2421.              c <<= 1;
  2422.             } while (++n & 07);
  2423.         }
  2424.         doprintf((" )"))
  2425.         break;
  2426.  
  2427. #ifdef obsolete
  2428.         case T_TXT:
  2429.         /* if (dlen > 0) */
  2430.         {
  2431.             doprintf(("\t\"%s\"", stoa(cp, dlen, TRUE)))
  2432.             cp += dlen;
  2433.         }
  2434.         break;
  2435. #endif
  2436.  
  2437.         case T_TXT:
  2438.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2439.             break;
  2440.         n = *cp++;
  2441.         doprintf(("\t\"%s\"", stoa(cp, n, TRUE)))
  2442.         cp += n;
  2443.  
  2444.         while (cp < eor)
  2445.         {
  2446.             if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2447.                 break;
  2448.             n = *cp++;
  2449.             doprintf((" \"%s\"", stoa(cp, n, TRUE)))
  2450.             cp += n;
  2451.         }
  2452.         break;
  2453.  
  2454.         case T_MINFO:
  2455.         n = expand_name(rname, type, cp, msg, eom, dname);
  2456.         if (n < 0)
  2457.             break;
  2458.         doprintf(("\t%s", pr_name(dname)))
  2459.         cp += n;
  2460.  
  2461.         n = expand_name(rname, type, cp, msg, eom, dname);
  2462.         if (n < 0)
  2463.             break;
  2464.         doprintf((" %s", pr_name(dname)))
  2465.         cp += n;
  2466.         break;
  2467.  
  2468.         case T_MB:
  2469.         case T_MG:
  2470.         case T_MR:
  2471.         case T_MD:
  2472.         case T_MF:
  2473.         n = expand_name(rname, type, cp, msg, eom, dname);
  2474.         if (n < 0)
  2475.             break;
  2476.         doprintf(("\t%s", pr_name(dname)))
  2477.         cp += n;
  2478.         break;
  2479.  
  2480.         case T_UID:
  2481.         case T_GID:
  2482.         if (dlen == INT32SZ)
  2483.         {
  2484.             n = _getlong(cp);
  2485.             doprintf(("\t%s", itoa(n)))
  2486.             cp += INT32SZ;
  2487.         }
  2488.         break;
  2489.  
  2490.         case T_UINFO:
  2491.         doprintf(("\t\"%s\"", stoa(cp, dlen, TRUE)))
  2492.         cp += dlen;
  2493.         break;
  2494.  
  2495.         case T_RP:
  2496.         n = expand_name(rname, type, cp, msg, eom, dname);
  2497.         if (n < 0)
  2498.             break;
  2499.         doprintf(("\t%s", pr_name(dname)))
  2500.         cp += n;
  2501.  
  2502.         n = expand_name(rname, type, cp, msg, eom, dname);
  2503.         if (n < 0)
  2504.             break;
  2505.         doprintf((" %s", pr_name(dname)))
  2506.         cp += n;
  2507.         break;
  2508.  
  2509.         case T_RT:
  2510.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2511.             break;
  2512.         n = _getshort(cp);
  2513.         doprintf(("\t%s", itoa(n)))
  2514.         cp += INT16SZ;
  2515.  
  2516.         n = expand_name(rname, type, cp, msg, eom, dname);
  2517.         if (n < 0)
  2518.             break;
  2519.         doprintf((" %s", pr_name(dname)))
  2520.         cp += n;
  2521.         break;
  2522.  
  2523.         case T_AFSDB:
  2524.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2525.             break;
  2526.         n = _getshort(cp);
  2527.         doprintf(("\t%s", itoa(n)))
  2528.         cp += INT16SZ;
  2529.  
  2530.         n = expand_name(rname, type, cp, msg, eom, dname);
  2531.         if (n < 0)
  2532.             break;
  2533.         doprintf((" %s", pr_name(dname)))
  2534.         cp += n;
  2535.         break;
  2536.  
  2537.         case T_X25:
  2538.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2539.             break;
  2540.         n = *cp++;
  2541.         doprintf(("\t%s", stoa(cp, n, FALSE)))
  2542.         cp += n;
  2543.         break;
  2544.  
  2545.         case T_ISDN:
  2546.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2547.             break;
  2548.         n = *cp++;
  2549.         doprintf(("\t%s", stoa(cp, n, FALSE)))
  2550.         cp += n;
  2551.  
  2552.         if (cp < eor)
  2553.         {
  2554.             if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2555.                 break;
  2556.             n = *cp++;
  2557.             doprintf((" %s", stoa(cp, n, FALSE)))
  2558.             cp += n;
  2559.         }
  2560.         break;
  2561.  
  2562.         case T_NSAP:
  2563.         doprintf(("\t0x%s", nsap_ntoa(cp, dlen)))
  2564.         cp += dlen;
  2565.         break;
  2566.  
  2567.         case T_NSAPPTR:
  2568.         n = expand_name(rname, type, cp, msg, eom, dname);
  2569.         if (n < 0)
  2570.             break;
  2571.         doprintf(("\t%s", pr_name(dname)))
  2572.         cp += n;
  2573.         break;
  2574.  
  2575.         case T_PX:
  2576.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2577.             break;
  2578.         n = _getshort(cp);
  2579.         doprintf(("\t%s", itoa(n)))
  2580.         cp += INT16SZ;
  2581.  
  2582.         n = expand_name(rname, type, cp, msg, eom, dname);
  2583.         if (n < 0)
  2584.             break;
  2585.         doprintf((" %s", pr_name(dname)))
  2586.         cp += n;
  2587.  
  2588.         n = expand_name(rname, type, cp, msg, eom, dname);
  2589.         if (n < 0)
  2590.             break;
  2591.         doprintf((" %s", pr_name(dname)))
  2592.         cp += n;
  2593.         break;
  2594.  
  2595.         case T_GPOS:
  2596.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2597.             break;
  2598.         n = *cp++;
  2599.         doprintf(("\t%s", stoa(cp, n, FALSE)))
  2600.         cp += n;
  2601.  
  2602.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2603.             break;
  2604.         n = *cp++;
  2605.         doprintf(("\t%s", stoa(cp, n, FALSE)))
  2606.         cp += n;
  2607.  
  2608.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2609.             break;
  2610.         n = *cp++;
  2611.         doprintf(("\t%s", stoa(cp, n, FALSE)))
  2612.         cp += n;
  2613.         break;
  2614.  
  2615.         case T_LOC:
  2616.         if ((n = *cp) != T_LOC_VERSION)
  2617.         {
  2618.             pr_error("invalid version %s in %s record for %s",
  2619.                 itoa(n), pr_type(type), rname);
  2620.             cp += dlen;
  2621.             break;
  2622.         }
  2623.  
  2624.         n = INT32SZ + 3*INT32SZ;
  2625.         if (check_size(rname, type, cp, msg, eor, n) < 0)
  2626.             break;
  2627.         c = _getlong(cp);
  2628.         cp += INT32SZ;
  2629.  
  2630.         n = _getlong(cp);
  2631.         doprintf(("\t%s ", pr_spherical(n, "N", "S")))
  2632.         cp += INT32SZ;
  2633.  
  2634.         n = _getlong(cp);
  2635.         doprintf((" %s ", pr_spherical(n, "E", "W")))
  2636.         cp += INT32SZ;
  2637.  
  2638.         n = _getlong(cp);
  2639.         doprintf((" %sm ", pr_vertical(n, "", "-")))
  2640.         cp += INT32SZ;
  2641.  
  2642.         doprintf((" %sm", pr_precision((c >> 16) & 0xff)))
  2643.         doprintf((" %sm", pr_precision((c >>  8) & 0xff)))
  2644.         doprintf((" %sm", pr_precision((c >>  0) & 0xff)))
  2645.         break;
  2646.  
  2647.         case T_UNSPEC:
  2648.         case T_NULL:
  2649.         cp += dlen;
  2650.         break;
  2651.  
  2652.         case T_AAAA:
  2653.         if (dlen == IPNGSIZE)
  2654.         {
  2655.             doprintf(("\t%s", ipng_ntoa(cp)))
  2656.             cp += IPNGSIZE;
  2657.         }
  2658.         break;
  2659.  
  2660.         case T_SIG:
  2661.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2662.             break;
  2663.         n = _getshort(cp);
  2664.         doprintf(("\t%s", pr_type(n)))
  2665.         cp += INT16SZ;
  2666.  
  2667.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2668.             break;
  2669.         n = *cp++;
  2670.         doprintf((" %s", itoa(n)))
  2671.  
  2672.         n = 1 + 3*INT32SZ + INT16SZ;
  2673.         if (check_size(rname, type, cp, msg, eor, n) < 0)
  2674.             break;
  2675.         doprintf((" ("))
  2676.  
  2677.         n = *cp++;
  2678.         doprintf(("\n\t\t\t; %s", itoa(n)))
  2679.         doprintf(("\t\t;labels"))
  2680.  
  2681.         n = _getlong(cp);
  2682.         doprintf(("\n\t\t\t%s", itoa(n)))
  2683.         doprintf(("\t\t;original ttl"))
  2684.         cp += INT32SZ;
  2685.  
  2686.         n = _getlong(cp);
  2687.         doprintf(("\n\t\t\t%s", pr_date(n)))
  2688.         doprintf(("\t;signature expiration"))
  2689.         cp += INT32SZ;
  2690.  
  2691.         n = _getlong(cp);
  2692.         doprintf(("\n\t\t\t%s", pr_date(n)))
  2693.         doprintf(("\t;signature signed time"))
  2694.         cp += INT32SZ;
  2695.  
  2696.         n = _getshort(cp);
  2697.         doprintf(("\n\t\t\t%s", itoa(n)))
  2698.         doprintf(("\t\t;key footprint"))
  2699.         cp += INT16SZ;
  2700.  
  2701.         n = expand_name(rname, type, cp, msg, eom, dname);
  2702.         if (n < 0)
  2703.             break;
  2704.         doprintf(("\n\t\t\t%s", pr_name(dname)))
  2705.         cp += n;
  2706.  
  2707.         if (cp < eor)
  2708.         {
  2709.             register char *buf;
  2710.             register int size;
  2711.  
  2712.             n = eor - cp;
  2713.             buf = base_ntoa(cp, n);
  2714.             size = strlength(buf);
  2715.             cp += n;
  2716.  
  2717.             while ((n = (size > 64) ? 64 : size) > 0)
  2718.             {
  2719.                 doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE)))
  2720.                 buf += n; size -= n;
  2721.             }
  2722.         }
  2723.  
  2724.         doprintf(("\n\t\t\t)"))
  2725.         break;
  2726.  
  2727.         case T_KEY:
  2728.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2729.             break;
  2730.         n = _getshort(cp);
  2731.         doprintf(("\t0x%s", xtoa(n)))
  2732.         cp += INT16SZ;
  2733.  
  2734.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2735.             break;
  2736.         n = *cp++;
  2737.         doprintf((" %s", itoa(n)))
  2738.  
  2739.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2740.             break;
  2741.         n = *cp++;
  2742.         doprintf((" %s", itoa(n)))
  2743.  
  2744.         if (cp < eor)
  2745.         {
  2746.             register char *buf;
  2747.             register int size;
  2748.  
  2749.             n = eor - cp;
  2750.             buf = base_ntoa(cp, n);
  2751.             size = strlength(buf);
  2752.             cp += n;
  2753.  
  2754.             doprintf((" ("))
  2755.             while ((n = (size > 64) ? 64 : size) > 0)
  2756.             {
  2757.                 doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE)))
  2758.                 buf += n; size -= n;
  2759.             }
  2760.             doprintf(("\n\t\t\t)"))
  2761.         }
  2762.         break;
  2763.  
  2764.         case T_NXT:
  2765.         n = expand_name(rname, type, cp, msg, eom, dname);
  2766.         if (n < 0)
  2767.             break;
  2768.         doprintf(("\t%s", pr_name(dname)))
  2769.         cp += n;
  2770.  
  2771.         n = 0;
  2772.         while (cp < eor)
  2773.         {
  2774.             c = *cp++;
  2775.             do
  2776.             {
  2777.              if (c & 0200)
  2778.             {
  2779.                 doprintf((" %s", pr_type(n)))
  2780.             }
  2781.              c <<= 1;
  2782.             } while (++n & 07);
  2783.         }
  2784.         break;
  2785.  
  2786.         case T_SRV:
  2787.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2788.             break;
  2789.         n = _getshort(cp);
  2790.         doprintf(("\t%s", itoa(n)))
  2791.         cp += INT16SZ;
  2792.  
  2793.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2794.             break;
  2795.         n = _getshort(cp);
  2796.         doprintf((" %s", itoa(n)))
  2797.         cp += INT16SZ;
  2798.  
  2799.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2800.             break;
  2801.         n = _getshort(cp);
  2802.         doprintf((" %s", itoa(n)))
  2803.         cp += INT16SZ;
  2804.  
  2805.         n = expand_name(rname, type, cp, msg, eom, dname);
  2806.         if (n < 0)
  2807.             break;
  2808.         doprintf((" %s", pr_name(dname)))
  2809.         cp += n;
  2810.         break;
  2811.  
  2812.         case T_EID:
  2813.         case T_NIMLOC:
  2814.         case T_ATMA:
  2815.         doprintf(("\t\"not yet implemented\""))
  2816.         cp += dlen;
  2817.         break;
  2818.  
  2819.         case T_NAPTR:
  2820.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2821.             break;
  2822.         n = _getshort(cp);
  2823.         doprintf(("\t%s", itoa(n)))
  2824.         cp += INT16SZ;
  2825.  
  2826.         if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0)
  2827.             break;
  2828.         n = _getshort(cp);
  2829.         doprintf((" %s", itoa(n)))
  2830.         cp += INT16SZ;
  2831.  
  2832.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2833.             break;
  2834.         n = *cp++;
  2835.         doprintf((" \"%s\"", stoa(cp, n, TRUE)))
  2836.         cp += n;
  2837.  
  2838.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2839.             break;
  2840.         n = *cp++;
  2841.         doprintf((" \"%s\"", stoa(cp, n, TRUE)))
  2842.         cp += n;
  2843.  
  2844.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2845.             break;
  2846.         n = *cp++;
  2847.         doprintf((" \"%s\"", stoa(cp, n, TRUE)))
  2848.         cp += n;
  2849.  
  2850.         n = expand_name(rname, type, cp, msg, eom, dname);
  2851.         if (n < 0)
  2852.             break;
  2853.         doprintf((" %s", pr_name(dname)))
  2854.         cp += n;
  2855.         break;
  2856. #ifdef notyet
  2857.         case T_TSIG:
  2858.         if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2859.             break;
  2860.         n = *cp++;
  2861.         doprintf(("\t\"%s\"", stoa(cp, n, TRUE)))
  2862.         cp += n;
  2863.  
  2864.         while (cp < eor)
  2865.         {
  2866.             if (check_size(rname, type, cp, msg, eor, 1) < 0)
  2867.                 break;
  2868.             n = *cp++;
  2869.             doprintf((" \"%s\"", stoa(cp, n, TRUE)))
  2870.             cp += n;
  2871.         }
  2872.         break;
  2873. #endif
  2874.         default:
  2875.         doprintf(("\t\"???\""))
  2876.         cp += dlen;
  2877.         break;
  2878.     }
  2879.  
  2880. /*
  2881.  * End of specific data type processing.
  2882.  * Terminate resource record printout.
  2883.  */
  2884.     doprintf(("\n"))
  2885.  
  2886. /*
  2887.  * Check whether we have reached the exact end of this resource record.
  2888.  * If not, we cannot be sure that the record has been decoded correctly,
  2889.  * and therefore the subsequent tests will be skipped.
  2890.  */
  2891.     if (cp != eor)
  2892.     {
  2893.         pr_error("size error in %s record for %s, off by %s",
  2894.             pr_type(type), rname, itoa(cp - eor));
  2895.  
  2896.         /* we believe value of dlen; should perhaps return(NULL) */
  2897.         return(eor);
  2898.     }
  2899.  
  2900. /*
  2901.  * Save the CNAME alias for cname chain tracing.
  2902.  * Save the MR or MG alias for MB chain tracing.
  2903.  * These features can be enabled only in normal mode.
  2904.  */
  2905.     if (regular && classmatch)
  2906.     {
  2907.         if (type == T_CNAME)
  2908.             cname = strcpy(cnamebuf, dname);
  2909.  
  2910.         else if (type == T_MR || type == T_MG)
  2911.             mname = strcpy(mnamebuf, dname);
  2912.     }
  2913.  
  2914. /*
  2915.  * Suppress the subsequent checks in quiet mode.
  2916.  * This can safely be done as there are no side effects.
  2917.  * It may speedup things, and nothing would be printed anyway.
  2918.  */
  2919.     if (quiet)
  2920.         return(cp);
  2921.  
  2922. /*
  2923.  * In zone listings, resource records with the same name/type/class
  2924.  * must have the same ttl value. Maintain and check list of record info.
  2925.  * This is done on a per-zone basis.
  2926.  */
  2927.     if (listing && !check_ttl(rname, type, class, ttl))
  2928.     {
  2929.         pr_warning("%s %s records have different ttl within %s from %s",
  2930.             rname, pr_type(type), name, host);
  2931.     }
  2932.  
  2933. /*
  2934.  * Check validity of 'host' related domain names in certain resource records.
  2935.  * These include LHS record names and RHS domain names of selected records.
  2936.  * Currently underscores are not reported during deep recursive listings.
  2937.  */
  2938.     if (test_valid(type) && !valid_name(rname, TRUE, FALSE, recurskip))
  2939.     {
  2940.         pr_warning("%s %s record has illegal name",
  2941.             rname, pr_type(type));
  2942.     }
  2943.  
  2944.     if (test_canon(type) && !valid_name(dname, FALSE, FALSE, recurskip))
  2945.     {
  2946.         pr_warning("%s %s host %s has illegal name",
  2947.             rname, pr_type(type), dname);
  2948.     }
  2949.  
  2950. /*
  2951.  * The RHS of various resource records should refer to a canonical host name,
  2952.  * i.e. it should exist and have an A record and not be a CNAME.
  2953.  * Currently this test is suppressed during deep recursive zone listings.
  2954.  */
  2955.     if (!recurskip && test_canon(type) && ((n = check_canon(dname)) != 0))
  2956.     {
  2957.         /* only report definitive target host failures */
  2958.         if (n == HOST_NOT_FOUND)
  2959.             pr_warning("%s %s host %s does not exist",
  2960.                 rname, pr_type(type), dname);
  2961.         else if (n == NO_DATA)
  2962.             pr_warning("%s %s host %s has no A record",
  2963.                 rname, pr_type(type), dname);
  2964.         else if (n == HOST_NOT_CANON)
  2965.             pr_warning("%s %s host %s is not canonical",
  2966.                 rname, pr_type(type), dname);
  2967.  
  2968.         /* authoritative failure to find nameserver target host */
  2969.         if (type == T_NS && (n == NO_DATA || n == HOST_NOT_FOUND))
  2970.         {
  2971.             if (server == NULL)
  2972.                 errmsg("%s has lame delegation to %s",
  2973.                     rname, dname);
  2974.         }
  2975.     }
  2976.  
  2977. /*
  2978.  * On request, reverse map the address of an A record, and verify that
  2979.  * it is registered and maps back to the name of the A record.
  2980.  * Currently this option has effect here only during zone listings.
  2981.  */
  2982.     if (addrmode && ((type == T_A) && !reverse) && !fakeaddr(address))
  2983.     {
  2984.         host = mapreverse(rname, inaddr);
  2985.         if (host == NULL)
  2986.             pr_warning("%s address %s is not registered",
  2987.                 rname, inet_ntoa(inaddr));
  2988.         else if (host != rname)
  2989.             pr_warning("%s address %s maps to %s",
  2990.                 rname, inet_ntoa(inaddr), host);
  2991.     }
  2992.  
  2993. /*
  2994.  * This record was processed successfully.
  2995.  */
  2996.     return(cp);
  2997. }
  2998.  
  2999. /*
  3000. ** SKIP_QREC -- Skip the query record in the nameserver answer buffer
  3001. ** ------------------------------------------------------------------
  3002. **
  3003. **    Returns:
  3004. **        Pointer to position in answer buffer after current record.
  3005. **        NULL if there was a format error in the current record.
  3006. */
  3007.  
  3008. u_char *
  3009. skip_qrec(name, qtype, qclass, cp, msg, eom)
  3010. input char *name;            /* full name we are querying about */
  3011. input int qtype;            /* record type we are querying about */
  3012. input int qclass;            /* record class we are querying about */
  3013. register u_char *cp;            /* current position in answer buf */
  3014. input u_char *msg, *eom;        /* begin and end of answer buf */
  3015. {
  3016.     char rname[MAXDNAME+1];        /* record name in LHS */
  3017.     int type, class;        /* fixed values in query record */
  3018.     register int n;
  3019.  
  3020. /*
  3021.  * Pickup the standard values present in the query section.
  3022.  */
  3023.     n = expand_name(name, T_NONE, cp, msg, eom, rname);
  3024.     if (n < 0)
  3025.         return(NULL);
  3026.     cp += n;
  3027.  
  3028.     n = 2*INT16SZ;
  3029.     if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  3030.         return(NULL);
  3031.  
  3032.     type = _getshort(cp);
  3033.     cp += INT16SZ;
  3034.  
  3035.     class = _getshort(cp);
  3036.     cp += INT16SZ;
  3037.  
  3038. #ifdef lint
  3039.     if (verbose)
  3040.         printf("%-20s\t%s\t%s\n",
  3041.             rname, pr_class(class), pr_type(type));
  3042. #endif
  3043.  
  3044. /*
  3045.  * The values in the answer should match those in the query.
  3046.  * If there is a mismatch, we just signal an error, but don't abort.
  3047.  * For regular queries there is exactly one record in the query section.
  3048.  */
  3049.     if (!sameword(rname, name))
  3050.         pr_error("invalid answer name %s after %s query for %s",
  3051.             rname, pr_type(qtype), name);
  3052.  
  3053.     if (type != qtype)
  3054.         pr_error("invalid answer type %s after %s query for %s",
  3055.             pr_type(type), pr_type(qtype), name);
  3056.  
  3057.     if (class != qclass)
  3058.         pr_error("invalid answer class %s after %s query for %s",
  3059.             pr_class(class), pr_type(qtype), name);
  3060.  
  3061.     return(cp);
  3062. }
  3063.  
  3064. /*
  3065. ** GET_RECURSIVE -- Wrapper for get_hostinfo() during recursion
  3066. ** ------------------------------------------------------------
  3067. **
  3068. **    Returns:
  3069. **        TRUE if requested info was obtained successfully.
  3070. **        FALSE otherwise.
  3071. */
  3072.  
  3073. bool
  3074. get_recursive(name)
  3075. input char **name;            /* name to query about */
  3076. {
  3077.     static int level = 0;        /* recursion level */
  3078.     char newnamebuf[MAXDNAME+1];
  3079.     char *newname;            /* new name to look up */
  3080.     bool result;            /* result status of action taken */
  3081.     int save_errno;
  3082.     int save_herrno;
  3083.  
  3084.     if (level > MAXCHAIN)
  3085.     {
  3086.         errmsg("Recursion too deep");
  3087.         return(FALSE);
  3088.     }
  3089.  
  3090.     /* save local copy, and reset indicator */
  3091.     newname = strcpy(newnamebuf, *name);
  3092.     *name = NULL;
  3093.  
  3094.     save_errno = errno;
  3095.     save_herrno = h_errno;
  3096.  
  3097.     level++;
  3098.     result = get_hostinfo(newname, TRUE);
  3099.     level--;
  3100.  
  3101.     errno = save_errno;
  3102.     h_errno = save_herrno;
  3103.  
  3104.     return(result);
  3105. }
  3106.  
  3107.  
  3108. /*
  3109.  * Nameserver information.
  3110.  * Stores names and addresses of all servers that are to be queried
  3111.  * for a zone transfer of the desired zone. Normally these are the
  3112.  * authoritative primary and/or secondary nameservers for the zone.
  3113.  */
  3114.  
  3115. char nsname[MAXNSNAME][MAXDNAME+1];        /* nameserver host name */
  3116. struct in_addr ipaddr[MAXNSNAME][MAXIPADDR];    /* nameserver addresses */
  3117. int naddrs[MAXNSNAME];                /* count of addresses */
  3118. int nservers = 0;                /* count of nameservers */
  3119.  
  3120. #ifdef notyet
  3121. typedef struct srvr_data {
  3122.     char sd_nsname[MAXDNAME+1];        /* nameserver host name */
  3123.     struct in_addr sd_ipaddr[MAXIPADDR];    /* nameserver addresses */
  3124.     int sd_naddrs;                /* count of addresses */
  3125. } srvr_data_t;
  3126.  
  3127. srvr_data_t nsinfo[MAXNSNAME];    /* nameserver info */
  3128. #endif
  3129.  
  3130. bool authserver;        /* server is supposed to be authoritative */
  3131. bool lameserver;        /* server could not provide SOA service */
  3132.  
  3133. /*
  3134.  * Host information.
  3135.  * Stores names and (single) addresses encountered during the zone listing
  3136.  * of all A records that belong to the zone. Non-authoritative glue records
  3137.  * that do not belong to the zone are not stored. Glue records that belong
  3138.  * to a delegated zone will be filtered out later during the host count scan.
  3139.  * The host names are allocated dynamically.
  3140.  * The list itself is also allocated dynamically, to avoid static limits,
  3141.  * and to keep the initial bss of the executable to a reasonable size.
  3142.  * Allocation is done in chunks, to reduce considerable malloc overhead.
  3143.  * Note that the list will not shrink during recursive processing.
  3144.  */
  3145.  
  3146. #ifdef obsolete
  3147. char *hostname[MAXHOSTS];    /* host name of host in zone */
  3148. ipaddr_t hostaddr[MAXHOSTS];    /* first host address */
  3149. bool multaddr[MAXHOSTS];    /* set if this is a multiple address host */
  3150. #endif
  3151.  
  3152. typedef struct host_data {
  3153.     char *hd_hostname;    /* host name of host in zone */
  3154.     ipaddr_t hd_hostaddr;    /* first host address */
  3155.     bool hd_multaddr;    /* set if this is a multiple address host */
  3156. } host_data_t;
  3157.  
  3158. host_data_t *hostlist = NULL;    /* info on hosts in zone */
  3159. int hostcount = 0;        /* count of hosts in zone */
  3160.  
  3161. int maxhosts = 0;        /* number of allocated hostlist entries */
  3162.  
  3163. #define MAXHOSTINCR    4096    /* chunk size to increment hostlist */
  3164.  
  3165. #define hostname(i)    hostlist[i].hd_hostname
  3166. #define hostaddr(i)    hostlist[i].hd_hostaddr
  3167. #define multaddr(i)    hostlist[i].hd_multaddr
  3168.  
  3169. /*
  3170.  * Delegated zone information.
  3171.  * Stores the names of the delegated zones encountered during the zone
  3172.  * listing. The names and the list itself are allocated dynamically.
  3173.  */
  3174.  
  3175. char **zonename = NULL;        /* names of delegated zones within zone */
  3176. int zonecount = 0;        /* count of delegated zones within zone */
  3177.  
  3178. /*
  3179.  * Address information.
  3180.  * Stores the (single) addresses of hosts found in all zones traversed.
  3181.  * Used to search for duplicate hosts (same address but different name).
  3182.  * The list of addresses is allocated dynamically, and remains allocated.
  3183.  * This has now been implemented as a hashed list, using the low-order
  3184.  * address bits as the hash key.
  3185.  */
  3186.  
  3187. #ifdef obsolete
  3188. ipaddr_t *addrlist = NULL;    /* global list of addresses */
  3189. int addrcount = 0;        /* count of global addresses */
  3190. #endif
  3191.  
  3192. /*
  3193.  * SOA record information.
  3194.  */
  3195.  
  3196. soa_data_t soa;            /* buffer to store soa data */
  3197.  
  3198. int soacount = 0;        /* count of SOA records during listing */
  3199.  
  3200. /*
  3201.  * Nameserver preference.
  3202.  * As per BIND 4.9.* resource records may be returned after round-robin
  3203.  * reshuffling each time they are retrieved. For NS records, this may
  3204.  * lead to an unfavorable order for doing zone transfers.
  3205.  * We apply some heuristic to sort the NS records according to their
  3206.  * preference with respect to a given list of preferred server domains.
  3207.  */
  3208.  
  3209. int nsrank[MAXNSNAME];        /* nameserver ranking after sorting */
  3210. int nspref[MAXNSNAME];        /* nameserver preference value */
  3211.  
  3212. /*
  3213. ** LIST_ZONE -- Basic routine to do complete zone listing and checking
  3214. ** -------------------------------------------------------------------
  3215. **
  3216. **    Returns:
  3217. **        TRUE if the requested info was processed successfully.
  3218. **        FALSE otherwise.
  3219. */
  3220.  
  3221. int total_calls = 0;        /* number of calls for zone processing */
  3222. int total_check = 0;        /* number of zones successfully processed */
  3223. int total_tries = 0;        /* number of zone transfer attempts */
  3224. int total_zones = 0;        /* number of successful zone transfers */
  3225. int total_hosts = 0;        /* number of hosts in all traversed zones */
  3226. int total_dupls = 0;        /* number of duplicates in all zones */
  3227.  
  3228. #ifdef justfun
  3229. char longname[MAXDNAME+1];    /* longest host name found */
  3230. int longsize = 0;        /* size of longest host name */
  3231. #endif
  3232.  
  3233. bool
  3234. list_zone(name)
  3235. input char *name;            /* name of zone to process */
  3236. {
  3237.     register int n;
  3238.     register int i;
  3239.     int nzones;            /* count of delegated zones */
  3240.     int nhosts;            /* count of real host names */
  3241.     int ndupls;            /* count of duplicate hosts */
  3242.     int nextrs;            /* count of extrazone hosts */
  3243.     int ngates;            /* count of gateway hosts */
  3244.  
  3245.     total_calls += 1;        /* update zone processing calls */
  3246.  
  3247. /*
  3248.  * Normalize to not have trailing dot, unless it is the root zone.
  3249.  */
  3250.     n = strlength(name);
  3251.     if (n > 1 && name[n-1] == '.')
  3252.         name[n-1] = '\0';
  3253.  
  3254. /*
  3255.  * Indicate whether we are processing an in-addr.arpa reverse zone.
  3256.  * In this case we will suppress accumulating host count statistics.
  3257.  */
  3258.     reverse = indomain(name, ARPA_ROOT, FALSE);
  3259.  
  3260. /*
  3261.  * Suppress various checks if working beyond the recursion skip level.
  3262.  * This affects processing in print_rrec(). It may need refinement.
  3263.  */
  3264.     recurskip = ((recursion_level > skip_level) && !addrmode) ? TRUE : FALSE;
  3265.  
  3266. /*
  3267.  * Find the nameservers for the given zone.
  3268.  */
  3269.     (void) find_servers(name);
  3270.  
  3271.     if (nservers < 1)
  3272.     {
  3273.         errmsg("No nameservers for %s found", name);
  3274.         return(FALSE);
  3275.     }
  3276.  
  3277. /*
  3278.  * Make sure we have an address for at least one nameserver.
  3279.  */
  3280.     for (n = 0; n < nservers; n++)
  3281.         if (naddrs[n] > 0)
  3282.             break;
  3283.  
  3284.     if (n >= nservers)
  3285.     {
  3286.         errmsg("No addresses of nameservers for %s found", name);
  3287.         return(FALSE);
  3288.     }
  3289.  
  3290. /*
  3291.  * Without an explicit server on the command line, the servers we
  3292.  * have looked up are supposed to be authoritative for the zone.
  3293.  */
  3294.     authserver = (server && !primary) ? FALSE : TRUE;
  3295.  
  3296. /*
  3297.  * Check SOA records at each of the nameservers if so requested.
  3298.  */
  3299.     if (checkmode)
  3300.     {
  3301.         do_check(name);
  3302.  
  3303.         total_check += 1;    /* update zones processed */
  3304.  
  3305.         /* all done if maximum recursion level reached */
  3306.         if (!recursive || (recursion_level >= recursive))
  3307.             return((errorcount == 0) ? TRUE : FALSE);
  3308.     }
  3309.  
  3310. /*
  3311.  * The zone transfer for certain zones can be skipped.
  3312.  * Currently this must be indicated on the command line.
  3313.  */
  3314.     if (skip_transfer(name))
  3315.     {
  3316.         if (verbose || statistics || checkmode || hostmode)
  3317.             printf("Skipping zone transfer for %s\n", name);
  3318.         return(FALSE);
  3319.     }
  3320.  
  3321. /*
  3322.  * Ask zone transfer to the nameservers, until one responds.
  3323.  */
  3324.     total_tries += 1;        /* update zone transfer attempts */
  3325.  
  3326.     if (!do_transfer(name))
  3327.         return(FALSE);
  3328.  
  3329.     total_zones += 1;        /* update successful zone transfers */
  3330.  
  3331. /*
  3332.  * Print resource record statistics if so requested.
  3333.  */
  3334.     if (statistics)
  3335.         print_statistics(name, querytype, queryclass);
  3336.  
  3337. /*
  3338.  * Accumulate host count statistics for this zone.
  3339.  * Do this only in modes in which such output would be printed.
  3340.  */
  3341.     nzones = zonecount;
  3342.  
  3343.     nhosts = 0, ndupls = 0, nextrs = 0, ngates = 0;
  3344.  
  3345.     i = (verbose || statistics || hostmode) ? 0 : hostcount;
  3346.  
  3347.     for (n = i; n < hostcount; n++)
  3348.     {
  3349.         /* skip fake hosts using a very rudimentary test */
  3350.         if (fakename(hostname(n)) || fakeaddr(hostaddr(n)))
  3351.             continue;
  3352. #ifdef justfun
  3353.         /* save longest host name encountered so far */
  3354.         if (verbose && ((i = strlength(hostname(n))) > longsize))
  3355.         {
  3356.             longsize = i;
  3357.             (void) strcpy(longname, hostname(n));
  3358.         }
  3359. #endif
  3360.         /* skip apparent glue records */
  3361.         if (gluerecord(hostname(n), name, zonename, nzones))
  3362.         {
  3363.             if (verbose > 1)
  3364.                 printf("%s is glue record\n", hostname(n));
  3365.             continue;
  3366.         }
  3367.  
  3368.         /* otherwise count as host */
  3369.         nhosts++;
  3370.  
  3371.     /*
  3372.      * Mark hosts not residing directly in the zone as extrazone host.
  3373.      */
  3374.         if (!samedomain(hostname(n), name, TRUE))
  3375.         {
  3376.             nextrs++;
  3377.             if (extrmode || (verbose > 1))
  3378.                 printf("%s is extrazone host\n", hostname(n));
  3379.         }
  3380.  
  3381.     /*
  3382.      * Mark hosts with more than one address as gateway host.
  3383.      * These are not checked for duplicate addresses.
  3384.      */
  3385.         if (multaddr(n))
  3386.         {
  3387.             ngates++;
  3388.             if (gatemode || (verbose > 1))
  3389.                 printf("%s is gateway host\n", hostname(n));
  3390.         }
  3391.         
  3392.     /*
  3393.      * Compare single address hosts against global list of addresses.
  3394.      * Multiple address hosts are too complicated to handle this way.
  3395.      */
  3396.         else if (check_dupl(hostaddr(n)))
  3397.         {
  3398.             struct in_addr inaddr;
  3399.             inaddr.s_addr = hostaddr(n);
  3400.  
  3401.             ndupls++;
  3402.             if (duplmode || (verbose > 1))
  3403.                 printf("%s is duplicate host with address %s\n",
  3404.                     hostname(n), inet_ntoa(inaddr));
  3405.         }
  3406.     }
  3407.  
  3408. /*
  3409.  * Print statistics for this zone.
  3410.  */
  3411.     if (verbose || statistics || hostmode)
  3412.     {
  3413.         printf("Found %d host%s within %s\n",
  3414.             nhosts, plural(nhosts), name);
  3415.  
  3416.         if ((ndupls > 0) || duplmode || (verbose > 1))
  3417.         printf("Found %d duplicate host%s within %s\n",
  3418.             ndupls, plural(ndupls), name);
  3419.  
  3420.         if ((nextrs > 0) || extrmode || (verbose > 1))
  3421.         printf("Found %d extrazone host%s within %s\n",
  3422.             nextrs, plural(nextrs), name);
  3423.  
  3424.         if ((ngates > 0) || gatemode || (verbose > 1))
  3425.         printf("Found %d gateway host%s within %s\n",
  3426.             ngates, plural(ngates), name);
  3427.     }
  3428.  
  3429.     total_hosts += nhosts;        /* update total number of hosts */
  3430.     total_dupls += ndupls;        /* update total number of duplicates */
  3431.  
  3432.     if (!checkmode)
  3433.         total_check += 1;    /* update zones processed */
  3434.  
  3435.     if (verbose || statistics)
  3436.         printf("Found %d delegated zone%s within %s\n",
  3437.             nzones, plural(nzones), name);
  3438.  
  3439. /*
  3440.  * Sort the encountered delegated zones alphabetically.
  3441.  * Note that this precludes further use of the zone_index() function.
  3442.  */
  3443.     if ((nzones > 1) && (recursive || listzones || mxdomains))
  3444.         qsort((ptr_t *)zonename, nzones, sizeof(char *), compare_name);
  3445.  
  3446. /*
  3447.  * The names of the hosts were allocated dynamically.
  3448.  */
  3449.     for (n = 0; n < hostcount; n++)
  3450.         xfree(hostname(n));
  3451.  
  3452. /*
  3453.  * Check for mailable delegated zones within this zone.
  3454.  * This is based on ordinary MX lookup, and not on the MX info
  3455.  * which may be present in the zone listing, to reduce zone transfers.
  3456.  */
  3457.     if (mxdomains)
  3458.     {
  3459.         if (recursion_level == 0)
  3460.         {
  3461.             if (verbose)
  3462.                 printf("\n");
  3463.  
  3464.             if (!get_mxrec(name))
  3465.                 ns_error(name, T_MX, queryclass, server);
  3466.         }
  3467.  
  3468.         for (n = 0; n < nzones; n++)
  3469.         {
  3470.             if (verbose)
  3471.                 printf("\n");
  3472.  
  3473.             if (!get_mxrec(zonename[n]))
  3474.                 ns_error(zonename[n], T_MX, queryclass, server);
  3475.         }
  3476.     }
  3477.  
  3478. /*
  3479.  * Do recursion on delegated zones if requested and any were found.
  3480.  * Temporarily save zonename list, and force allocation of new list.
  3481.  */
  3482.     if (recursive && (recursion_level < recursive))
  3483.     {
  3484.         for (n = 0; n < nzones; n++)
  3485.         {
  3486.             char **newzone;        /* local copy of list */
  3487.  
  3488.             newzone = zonename;
  3489.             zonename = NULL;    /* allocate new list */
  3490.  
  3491.             if (verbose || statistics || checkmode || hostmode)
  3492.                 printf("\n");
  3493.  
  3494.             if (listzones)
  3495.             {
  3496.                 for (i = 0; i <= recursion_level; i++)
  3497.                     printf("%s", (i == 0) ? "\t" : "  ");
  3498.                 printf("%s\n", newzone[n]);
  3499.             }
  3500.  
  3501.             if (verbose)
  3502.                 printf("Entering zone %s\n", newzone[n]);
  3503.  
  3504.             recursion_level++;
  3505.             (void) list_zone(newzone[n]);
  3506.             recursion_level--;
  3507.  
  3508.             zonename = newzone;    /* restore */
  3509.         }
  3510.     }
  3511.     else if (listzones)
  3512.     {
  3513.         for (n = 0; n < nzones; n++)
  3514.         {
  3515.             for (i = 0; i <= recursion_level; i++)
  3516.                 printf("%s", (i == 0) ? "\t" : "  ");
  3517.             printf("%s\n", zonename[n]);
  3518.         }
  3519.     }
  3520.  
  3521. /*
  3522.  * The names of the delegated zones were allocated dynamically.
  3523.  * The list of delegated zone names was also allocated dynamically.
  3524.  */
  3525.     for (n = 0; n < nzones; n++)
  3526.         xfree(zonename[n]);
  3527.  
  3528.     if (zonename != NULL)
  3529.         xfree(zonename);
  3530.  
  3531.     zonename = NULL;
  3532.  
  3533. /*
  3534.  * Print final overall statistics.
  3535.  */
  3536.     if (recursive && (recursion_level == 0))
  3537.     {
  3538.         if (verbose || statistics || checkmode || hostmode)
  3539.             printf("\n");
  3540.  
  3541.         if (verbose || statistics || hostmode)
  3542.             printf("Encountered %d host%s in %d zone%s within %s\n",
  3543.                 total_hosts, plural(total_hosts),
  3544.                 total_zones, plural(total_zones),
  3545.                 name);
  3546.  
  3547.         if (verbose || statistics || hostmode)
  3548.             printf("Encountered %d duplicate host%s in %d zone%s within %s\n",
  3549.                 total_dupls, plural(total_dupls),
  3550.                 total_zones, plural(total_zones),
  3551.                 name);
  3552.  
  3553.         if (verbose || statistics || checkmode)
  3554.             printf("Transferred %d zone%s out of %d attempt%s\n",
  3555.                 total_zones, plural(total_zones),
  3556.                 total_tries, plural(total_tries));
  3557.  
  3558.         if (verbose || statistics || checkmode)
  3559.             printf("Processed %d zone%s out of %d request%s\n",
  3560.                 total_check, plural(total_check),
  3561.                 total_calls, plural(total_calls));
  3562. #ifdef justfun
  3563.         if (verbose && (longsize > 0))
  3564.             printf("Longest hostname %s\t%d\n",
  3565.                 longname, longsize);
  3566. #endif
  3567.     }
  3568.  
  3569.     /* indicate whether any errors were encountered */
  3570.     return((errorcount == 0) ? TRUE : FALSE);
  3571. }
  3572.  
  3573. /*
  3574. ** FIND_SERVERS -- Fetch names and addresses of authoritative servers
  3575. ** ------------------------------------------------------------------
  3576. **
  3577. **    Returns:
  3578. **        TRUE if servers could be determined successfully.
  3579. **        FALSE otherwise.
  3580. **
  3581. **    Inputs:
  3582. **        The global variable ``server'', if set, contains the
  3583. **        name of the explicit server to be contacted.
  3584. **        The global variable ``primary'', if set, indicates
  3585. **        that we must use the primary nameserver for the zone.
  3586. **        If both are set simultaneously, the explicit server
  3587. **        is contacted to retrieve the desired servers.
  3588. **
  3589. **    Outputs:
  3590. **        The count of nameservers is stored in ``nservers''.
  3591. **        Names are stored in the nsname[] database.
  3592. **        Addresses are stored in the ipaddr[] database.
  3593. **        Address counts are stored in the naddrs[] database.
  3594. */
  3595.  
  3596. bool
  3597. find_servers(name)
  3598. input char *name;            /* name of zone to find servers for */
  3599. {
  3600.     struct hostent *hp;
  3601.     register int n, i;
  3602.  
  3603. /*
  3604.  * Use the explicit server if given on the command line.
  3605.  * Its addresses are stored in the resolver state struct.
  3606.  * This server may not be authoritative for the given zone.
  3607.  */
  3608.     if (server && !primary)
  3609.     {
  3610.         (void) strcpy(nsname[0], server);
  3611.  
  3612.         for (i = 0; i < MAXIPADDR && i < _res.nscount; i++)
  3613.             ipaddr[0][i] = nslist(i).sin_addr;
  3614.         naddrs[0] = i;
  3615.  
  3616.         nservers = 1;
  3617.         return(TRUE);
  3618.     }
  3619.  
  3620. /*
  3621.  * Fetch primary nameserver info if so requested.
  3622.  * Get its name from the SOA record for the zone, and do a regular
  3623.  * host lookup to fetch its addresses. We are assuming here that the
  3624.  * SOA record is a proper one. This is not necessarily true.
  3625.  * Obviously this server should be authoritative.
  3626.  */
  3627.     if (primary && !server)
  3628.     {
  3629.         char *primaryname;
  3630.  
  3631.         primaryname = get_primary(name);
  3632.         if (primaryname == NULL)
  3633.         {
  3634.             ns_error(name, T_SOA, queryclass, server);
  3635.             nservers = 0;
  3636.             return(FALSE);
  3637.         }
  3638.  
  3639.         hp = geth_byname(primaryname);
  3640.         if (hp == NULL)
  3641.         {
  3642.             ns_error(primaryname, T_A, C_IN, server);
  3643.             nservers = 0;
  3644.             return(FALSE);
  3645.         }
  3646.  
  3647.         primaryname = strncpy(nsname[0], hp->h_name, MAXDNAME);
  3648.         primaryname[MAXDNAME] = '\0';
  3649.  
  3650.         for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
  3651.             ipaddr[0][i] = incopy(hp->h_addr_list[i]);
  3652.         naddrs[0] = i;
  3653.  
  3654.         if (verbose)
  3655.             printf("Found %d address%s for %s\n",
  3656.                 naddrs[0], plurale(naddrs[0]), nsname[0]);
  3657.         nservers = 1;
  3658.         return(TRUE);
  3659.     }
  3660.  
  3661. /*
  3662.  * Otherwise we have to find the nameservers for the zone.
  3663.  * These are supposed to be authoritative, but sometimes we
  3664.  * encounter lame delegations, perhaps due to misconfiguration.
  3665.  */
  3666.     if (!get_servers(name))
  3667.     {
  3668.         ns_error(name, T_NS, queryclass, server);
  3669.         nservers = 0;
  3670.         return(FALSE);
  3671.     }
  3672.  
  3673. /*
  3674.  * Usually we'll get addresses for all the servers in the additional
  3675.  * info section.  But in case we don't, look up their addresses.
  3676.  * Addresses could be missing because there is no room in the answer.
  3677.  * No address is present if the name of a server is not canonical.
  3678.  * If we get no addresses by extra query, and this is authoritative,
  3679.  * we flag a lame delegation to that server.
  3680.  */
  3681.     for (n = 0; n < nservers; n++)
  3682.     {
  3683.         if (naddrs[n] == 0)
  3684.         {
  3685.         hp = geth_byname(nsname[n]);
  3686.         if (hp != NULL)
  3687.         {
  3688.             for (i = 0; i < MAXIPADDR && hp->h_addr_list[i]; i++)
  3689.                 ipaddr[n][i] = incopy(hp->h_addr_list[i]);
  3690.             naddrs[n] = i;
  3691.         }
  3692.  
  3693.         if (verbose)
  3694.             printf("Found %d address%s for %s by extra query\n",
  3695.                 naddrs[n], plurale(naddrs[n]), nsname[n]);
  3696.  
  3697.         if (hp == NULL)
  3698.         {
  3699.             /* server name lookup failed */
  3700.             ns_error(nsname[n], T_A, C_IN, server);
  3701.  
  3702.             /* authoritative denial: probably misconfiguration */
  3703.             if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
  3704.             {
  3705.                 if (server == NULL)
  3706.                     errmsg("%s has lame delegation to %s",
  3707.                         name, nsname[n]);
  3708.             }
  3709.         }
  3710.  
  3711.         if ((hp != NULL) && !sameword(hp->h_name, nsname[n]))
  3712.             pr_warning("%s nameserver %s is not canonical (%s)",
  3713.                 name, nsname[n], hp->h_name);
  3714.         }
  3715.         else
  3716.         {
  3717.         if (verbose)
  3718.             printf("Found %d address%s for %s\n",
  3719.                 naddrs[n], plurale(naddrs[n]), nsname[n]);
  3720.         }
  3721.     }
  3722.  
  3723. /*
  3724.  * Issue warning if only one server has been discovered.
  3725.  * This is not an error per se, but not much redundancy in that case.
  3726.  */
  3727.     if (nservers == 1)
  3728.         pr_warning("%s has only one nameserver %s",
  3729.             name, nsname[0]);
  3730.  
  3731.     return((nservers > 0) ? TRUE : FALSE);
  3732. }
  3733.  
  3734. /*
  3735. ** GET_SERVERS -- Fetch names and addresses of authoritative servers
  3736. ** -----------------------------------------------------------------
  3737. **
  3738. **    Returns:
  3739. **        TRUE if servers could be determined successfully.
  3740. **        FALSE otherwise.
  3741. **
  3742. **    Side effects:
  3743. **        The count of nameservers is stored in ``nservers''.
  3744. **        Names are stored in the nsname[] database.
  3745. **        Addresses are stored in the ipaddr[] database.
  3746. **        Address counts are stored in the naddrs[] database.
  3747. */
  3748.  
  3749. bool
  3750. get_servers(name)
  3751. input char *name;            /* name of zone to find servers for */
  3752. {
  3753.     querybuf answer;
  3754.     register int n;
  3755.     bool result;            /* result status of action taken */
  3756.  
  3757.     if (verbose)
  3758.         printf("Finding nameservers for %s ...\n", name);
  3759.  
  3760.     n = get_info(&answer, name, T_NS, queryclass);
  3761.     if (n < 0)
  3762.         return(FALSE);
  3763.  
  3764.     if (verbose > 1)
  3765.         (void) print_info(&answer, n, name, T_NS, queryclass, FALSE);
  3766.  
  3767.     result = get_nsinfo(&answer, n, name);
  3768.     return(result);
  3769. }
  3770.  
  3771. /*
  3772. ** GET_NSINFO -- Extract nameserver data from nameserver answer buffer
  3773. ** -------------------------------------------------------------------
  3774. **
  3775. **    Returns:
  3776. **        TRUE if the answer buffer was processed successfully.
  3777. **        FALSE otherwise.
  3778. **
  3779. **    Outputs:
  3780. **        The count of nameservers is stored in ``nservers''.
  3781. **        Names are stored in the nsname[] database.
  3782. **        Addresses are stored in the ipaddr[] database.
  3783. **        Address counts are stored in the naddrs[] database.
  3784. */
  3785.  
  3786. bool
  3787. get_nsinfo(answerbuf, answerlen, name)
  3788. input querybuf *answerbuf;        /* location of answer buffer */
  3789. input int answerlen;            /* length of answer buffer */
  3790. input char *name;            /* name of zone to find servers for */
  3791. {
  3792.     HEADER *bp;
  3793.     int qdcount, ancount, nscount, arcount, rrcount;
  3794.     u_char *msg, *eom;
  3795.     register u_char *cp;
  3796.     register int i;
  3797.  
  3798.     nservers = 0;            /* count of nameservers */
  3799.  
  3800.     bp = (HEADER *)answerbuf;
  3801.     qdcount = ntohs(bp->qdcount);
  3802.     ancount = ntohs(bp->ancount);
  3803.     nscount = ntohs(bp->nscount);
  3804.     arcount = ntohs(bp->arcount);
  3805.  
  3806.     msg = (u_char *)answerbuf;
  3807.     eom = (u_char *)answerbuf + answerlen;
  3808.     cp  = (u_char *)answerbuf + HFIXEDSZ;
  3809.  
  3810.     if (qdcount > 0 && cp < eom)    /* should be exactly one record */
  3811.     {
  3812.         cp = skip_qrec(name, T_NS, queryclass, cp, msg, eom);
  3813.         if (cp == NULL)
  3814.             return(FALSE);
  3815.         qdcount--;
  3816.     }
  3817.  
  3818.     if (qdcount)
  3819.     {
  3820.         pr_error("invalid qdcount after %s query for %s",
  3821.             pr_type(T_NS), name);
  3822.         h_errno = NO_RECOVERY;
  3823.         return(FALSE);
  3824.     }
  3825.  
  3826. /*
  3827.  * If the answer is authoritative, the names are found in the
  3828.  * answer section, and the nameserver section is empty.
  3829.  * If not, there may be duplicate names in both sections.
  3830.  * Addresses are found in the additional info section both cases.
  3831.  */
  3832.     rrcount = ancount + nscount + arcount;
  3833.     while (rrcount > 0 && cp < eom)
  3834.     {
  3835.         char rname[MAXDNAME+1];
  3836.         char dname[MAXDNAME+1];
  3837.         int type, class, ttl, dlen;
  3838.         u_char *eor;
  3839.         register int n;
  3840.         struct in_addr inaddr;
  3841.  
  3842.         n = expand_name(name, T_NONE, cp, msg, eom, rname);
  3843.         if (n < 0)
  3844.             return(FALSE);
  3845.         cp += n;
  3846.  
  3847.         n = 3*INT16SZ + INT32SZ;
  3848.         if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  3849.             return(FALSE);
  3850.  
  3851.         type = _getshort(cp);
  3852.         cp += INT16SZ;
  3853.  
  3854.         class = _getshort(cp);
  3855.         cp += INT16SZ;
  3856.  
  3857.         ttl = _getlong(cp);
  3858.         cp += INT32SZ;
  3859.  
  3860.         dlen = _getshort(cp);
  3861.         cp += INT16SZ;
  3862.  
  3863.         eor = cp + dlen;
  3864. #ifdef lint
  3865.         if (verbose)
  3866.             printf("%-20s\t%d\t%s\t%s\n",
  3867.                 rname, ttl, pr_class(class), pr_type(type));
  3868. #endif
  3869.         if ((type == T_NS) && sameword(rname, name))
  3870.         {
  3871.             n = expand_name(rname, type, cp, msg, eom, dname);
  3872.             if (n < 0)
  3873.                 return(FALSE);
  3874.             cp += n;
  3875.  
  3876.             for (i = 0; i < nservers; i++)
  3877.                 if (sameword(nsname[i], dname))
  3878.                     break;    /* duplicate */
  3879.  
  3880.             if (i >= nservers && nservers < MAXNSNAME)
  3881.             {
  3882.                 (void) strcpy(nsname[nservers], dname);
  3883.                 naddrs[nservers] = 0;
  3884.                 nservers++;
  3885.             }
  3886.         }
  3887.         else if ((type == T_A) && (dlen == INADDRSZ))
  3888.         {
  3889.             for (i = 0; i < nservers; i++)
  3890.                 if (sameword(nsname[i], rname))
  3891.                     break;    /* found */
  3892.  
  3893.             if (i < nservers && naddrs[i] < MAXIPADDR)
  3894.             {
  3895.                 bcopy((char *)cp, (char *)&inaddr, INADDRSZ);
  3896.                 ipaddr[i][naddrs[i]] = inaddr;
  3897.                 naddrs[i]++;
  3898.             }
  3899.  
  3900.             cp += dlen;
  3901.         }
  3902.         else
  3903.         {
  3904.             /* just ignore other records */
  3905.             cp += dlen;
  3906.         }
  3907.  
  3908.         if (cp != eor)
  3909.         {
  3910.             pr_error("size error in %s record for %s, off by %s",
  3911.                 pr_type(type), rname, itoa(cp - eor));
  3912.             h_errno = NO_RECOVERY;
  3913.             return(FALSE);
  3914.         }
  3915.  
  3916.         rrcount--;
  3917.     }
  3918.  
  3919.     if (rrcount)
  3920.     {
  3921.         pr_error("invalid rrcount after %s query for %s",
  3922.             pr_type(T_NS), name);
  3923.         h_errno = NO_RECOVERY;
  3924.         return(FALSE);
  3925.     }
  3926.  
  3927.     /* set proper status if no answers found */
  3928.     h_errno = (nservers > 0) ? 0 : TRY_AGAIN;
  3929.     return(TRUE);
  3930. }
  3931.  
  3932. /*
  3933. ** SORT_SERVERS -- Sort set of nameservers according to preference
  3934. ** ---------------------------------------------------------------
  3935. **
  3936. **    Returns:
  3937. **        None.
  3938. **
  3939. **    Inputs:
  3940. **        Set of nameservers as determined by find_servers().
  3941. **        The global variable ``prefserver'', if set, contains
  3942. **        a list of preferred server domains to compare against.
  3943. **
  3944. **    Outputs:
  3945. **        Stores the preferred nameserver order in nsrank[].
  3946. */
  3947.  
  3948. void
  3949. sort_servers()
  3950. {
  3951.     register int i, j;
  3952.     register int n, pref;
  3953.     register char *p, *q;
  3954.  
  3955. /*
  3956.  * Initialize the default ranking.
  3957.  */
  3958.     for (n = 0; n < nservers; n++)
  3959.     {
  3960.         nsrank[n] = n;
  3961.         nspref[n] = 0;
  3962.     }
  3963.  
  3964. /*
  3965.  * Determine the nameserver preference.
  3966.  * Compare against a list of comma-separated preferred server domains.
  3967.  * Use the maximum value of all comparisons.
  3968.  */
  3969.     for (q = NULL, p = prefserver; p != NULL; p = q)
  3970.     {
  3971.         q = index(p, ',');
  3972.         if (q != NULL)
  3973.             *q = '\0';
  3974.  
  3975.         for (n = 0; n < nservers; n++)
  3976.         {
  3977.             pref = matchlabels(nsname[n], p);
  3978.             if (pref > nspref[n])
  3979.                 nspref[n] = pref;
  3980.         }
  3981.  
  3982.         if (q != NULL)
  3983.             *q++ = ',';
  3984.     }
  3985.  
  3986. /*
  3987.  * Sort the set according to preference.
  3988.  * Keep the rest as much as possible in original order.
  3989.  */
  3990.     for (i = 0; i < nservers; i++)
  3991.     {
  3992.         for (j = i + 1; j < nservers; j++)
  3993.         {
  3994.             if (nspref[j] > nspref[i])
  3995.             {
  3996.                 pref = nspref[j];
  3997.                 /* nspref[j] = nspref[i]; */
  3998.                 for (n = j; n > i; n--)
  3999.                     nspref[n] = nspref[n-1];
  4000.                 nspref[i] = pref;
  4001.  
  4002.                 pref = nsrank[j];
  4003.                 /* nsrank[j] = nsrank[i]; */
  4004.                 for (n = j; n > i; n--)
  4005.                     nsrank[n] = nsrank[n-1];
  4006.                 nsrank[i] = pref;
  4007.             }
  4008.         }
  4009.     }
  4010. }
  4011.  
  4012. /*
  4013. ** SKIP_TRANSFER -- Check whether a zone transfer should be skipped
  4014. ** ----------------------------------------------------------------
  4015. **
  4016. **    Returns:
  4017. **        TRUE if a transfer for this zone should be skipped.
  4018. **        FALSE if the zone transfer should proceed.
  4019. **
  4020. **    Inputs:
  4021. **        The global variable ``skipzone'', if set, contains
  4022. **        a list of zone names to be skipped.
  4023. **
  4024. **    Certain zones are known to contain bogus information, and
  4025. **    can be requested to be excluded from further processing.
  4026. **    The zone transfer for such zones and its delegated zones
  4027. **    will be skipped.
  4028. */
  4029.  
  4030. bool
  4031. skip_transfer(name)
  4032. input char *name;            /* name of zone to process */
  4033. {
  4034.     register char *p, *q;
  4035.     bool skip = FALSE;
  4036.  
  4037.     for (q = NULL, p = skipzone; p != NULL; p = q)
  4038.     {
  4039.         q = index(p, ',');
  4040.         if (q != NULL)
  4041.             *q = '\0';
  4042.  
  4043.         if (sameword(name, p))
  4044.             skip = TRUE;
  4045.  
  4046.         if (q != NULL)
  4047.             *q++ = ',';
  4048.     }
  4049.  
  4050.     return(skip);
  4051. }
  4052.  
  4053. /*
  4054. ** DO_CHECK -- Check SOA records at each of the nameservers
  4055. ** --------------------------------------------------------
  4056. **
  4057. **    Returns:
  4058. **        None.
  4059. **
  4060. **    Inputs:
  4061. **        The count of nameservers is stored in ``nservers''.
  4062. **        Names are stored in the nsname[] database.
  4063. **        Addresses are stored in the ipaddr[] database.
  4064. **        Address counts are stored in the naddrs[] database.
  4065. **
  4066. **    The SOA record of the zone is checked at each nameserver.
  4067. **    Nameserver recursion is turned off to make sure that the
  4068. **    answer is authoritative.
  4069. */
  4070.  
  4071. void
  4072. do_check(name)
  4073. input char *name;            /* name of zone to process */
  4074. {
  4075.     res_state_t save_res;        /* saved copy of resolver database */
  4076.     char *save_server;        /* saved copy of server name */
  4077.     register int n;
  4078.     register int i;
  4079.  
  4080.     /* save resolver database */
  4081.     save_res = _res;
  4082.     save_server = server;
  4083.  
  4084.     /* turn off nameserver recursion */
  4085.     _res.options &= ~RES_RECURSE;
  4086.  
  4087.     for (n = 0; n < nservers; n++)
  4088.     {
  4089.         if (naddrs[n] < 1)
  4090.             continue;    /* shortcut */
  4091.  
  4092.         server = nsname[n];
  4093.         for (i = 0; i < MAXNS && i < naddrs[n]; i++)
  4094.         {
  4095.             nslist(i).sin_family = AF_INET;
  4096.             nslist(i).sin_port = htons(NAMESERVER_PORT);
  4097.             nslist(i).sin_addr = ipaddr[n][i];
  4098.         }
  4099.         _res.nscount = i;
  4100.  
  4101.         /* retrieve and check SOA */
  4102.         if (check_zone(name))
  4103.             continue;
  4104.  
  4105.         /* SOA query failed */
  4106.         ns_error(name, T_SOA, queryclass, server);
  4107.  
  4108.         /* explicit server failure: possibly data expired */
  4109.         lameserver = (h_errno == SERVER_FAILURE) ? TRUE : FALSE;
  4110.  
  4111.         /* non-authoritative denial: assume lame delegation */
  4112.         if (h_errno == NO_RREC || h_errno == NO_HOST)
  4113.             lameserver = TRUE;
  4114.  
  4115.         /* authoritative denial: probably misconfiguration */
  4116.         if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
  4117.             lameserver = TRUE;
  4118.  
  4119.         /* flag an error if server should not have failed */
  4120.         if (lameserver && authserver)
  4121.             errmsg("%s has lame delegation to %s",
  4122.                 name, server);
  4123.     }
  4124.  
  4125.     /* restore resolver database */
  4126.     _res = save_res;
  4127.     server = save_server;
  4128. }
  4129.  
  4130. /*
  4131. ** DO_TRANSFER -- Perform a zone transfer from any of its nameservers
  4132. ** ------------------------------------------------------------------
  4133. **
  4134. **    Returns:
  4135. **        TRUE if the zone data have been retrieved successfully.
  4136. **        FALSE if none of the servers responded.
  4137. **
  4138. **    Inputs:
  4139. **        The count of nameservers is stored in ``nservers''.
  4140. **        Names are stored in the nsname[] database.
  4141. **        Addresses are stored in the ipaddr[] database.
  4142. **        Address counts are stored in the naddrs[] database.
  4143. **
  4144. **    Ask zone transfer to the nameservers, until one responds.
  4145. **    The list of nameservers is sorted according to preference.
  4146. **    An authoritative server should always respond positively.
  4147. **    If it responds with an error, we may have a lame delegation.
  4148. **    Always retry with the next server to avoid missing entire zones.
  4149. */
  4150.  
  4151. bool
  4152. do_transfer(name)
  4153. input char *name;            /* name of zone to do zone xfer for */
  4154. {
  4155.     register int n, ns;
  4156.     register int i;
  4157.  
  4158.     for (sort_servers(), ns = 0; ns < nservers; ns++)
  4159.     {
  4160.         for (n = nsrank[ns], i = 0; i < naddrs[n]; i++)
  4161.         {
  4162.         if (verbose)
  4163.             printf("Trying server %s (%s) ...\n",
  4164.                 inet_ntoa(ipaddr[n][i]), nsname[n]);
  4165.  
  4166.         if (transfer_zone(name, ipaddr[n][i], nsname[n]))
  4167.             goto done;    /* double break */
  4168.  
  4169.         /* zone transfer failed */
  4170.         if ((h_errno != TRY_AGAIN) || verbose)
  4171.             ns_error(name, T_AXFR, queryclass, nsname[n]);
  4172.  
  4173.         /* zone transfer request was explicitly refused */
  4174.         if (h_errno == QUERY_REFUSED)
  4175.             break;
  4176.  
  4177.         /* explicit server failure: possibly data expired */
  4178.         lameserver = (h_errno == SERVER_FAILURE) ? TRUE : FALSE;
  4179.  
  4180.         /* non-authoritative denial: assume lame delegation */
  4181.         if (h_errno == NO_RREC || h_errno == NO_HOST)
  4182.             lameserver = TRUE;
  4183.  
  4184.         /* authoritative denial: probably misconfiguration */
  4185.         if (h_errno == NO_DATA || h_errno == HOST_NOT_FOUND)
  4186.             lameserver = TRUE;
  4187.  
  4188.         /* flag an error if server should not have failed */
  4189.         if (lameserver && authserver)
  4190.             errmsg("%s has lame delegation to %s",
  4191.                 name, nsname[n]);
  4192.  
  4193.         /* try next server if this one is sick */
  4194.         if (lameserver)
  4195.             break;
  4196.  
  4197.         /* terminate on irrecoverable errors */
  4198.         if (h_errno != TRY_AGAIN)
  4199.             return(FALSE);
  4200.  
  4201.         /* in case nameserver not present */
  4202.         if (errno == ECONNREFUSED)
  4203.             break;
  4204.         }
  4205.     }
  4206. done:
  4207.     if (ns >= nservers)
  4208.     {
  4209.         if ((h_errno == TRY_AGAIN) && !verbose)
  4210.             ns_error(name, T_AXFR, queryclass, (char *)NULL);
  4211.         errmsg("No nameservers for %s responded", name);
  4212.         return(FALSE);
  4213.     }
  4214.  
  4215.     return(TRUE);
  4216. }
  4217.  
  4218. /*
  4219. ** TRANSFER_ZONE -- Wrapper for get_zone() to hide administrative tasks
  4220. ** --------------------------------------------------------------------
  4221. **
  4222. **    Returns:
  4223. **        See get_zone() for details.
  4224. **
  4225. **    Side effects:
  4226. **        See get_zone() for details.
  4227. **
  4228. **    This routine may be called repeatedly with different server
  4229. **    addresses, until one of the servers responds. Various items
  4230. **    must be reset on every try to continue with a clean slate.
  4231. */
  4232.  
  4233. bool
  4234. transfer_zone(name, inaddr, host)
  4235. input char *name;            /* name of zone to do zone xfer for */
  4236. input struct in_addr inaddr;        /* address of server to be queried */
  4237. input char *host;            /* name of server to be queried */
  4238. {
  4239.     register int n;
  4240.  
  4241. /*
  4242.  * Reset the resource record statistics before each try.
  4243.  */
  4244.     clear_statistics();
  4245.  
  4246. /*
  4247.  * Reset the hash tables of saved resource record information.
  4248.  * These tables are used only during the zone transfer itself.
  4249.  */
  4250.     clear_ttltab();
  4251.     clear_hosttab();
  4252.     clear_zonetab();
  4253.  
  4254. /*
  4255.  * Perform the actual zone transfer.
  4256.  * All error reporting is done by get_zone().
  4257.  */
  4258.     if (get_zone(name, inaddr, host))
  4259.         return(TRUE);
  4260.  
  4261. /*
  4262.  * Failure to get the zone. Free any memory that may have been allocated.
  4263.  * On success it is the responsibility of the caller to free the memory.
  4264.  * The information gathered is used by list_zone() after the zone transfer.
  4265.  */
  4266.     for (n = 0; n < hostcount; n++)
  4267.         xfree(hostname(n));
  4268.  
  4269.     for (n = 0; n < zonecount; n++)
  4270.         xfree(zonename[n]);
  4271.  
  4272.     if (zonename != NULL)
  4273.         xfree(zonename);
  4274.  
  4275.     zonename = NULL;
  4276.  
  4277.     return(FALSE);
  4278. }
  4279.  
  4280. /*
  4281. ** GET_ZONE -- Perform a zone transfer from server at specific address
  4282. ** -------------------------------------------------------------------
  4283. **
  4284. **    Returns:
  4285. **        TRUE if the zone data have been retrieved successfully.
  4286. **        FALSE if an error occurred (h_errno is set appropriately).
  4287. **        Set TRY_AGAIN wherever possible to try the next server.
  4288. **
  4289. **    Side effects:
  4290. **        Stores list of delegated zones found in zonename[],
  4291. **        and the count of delegated zones in ``zonecount''.
  4292. **        Stores list of host names found in hostname[],
  4293. **        and the count of host names in ``hostcount''.
  4294. **        Updates resource record statistics in record_stats[].
  4295. **        This array must have been cleared before.
  4296. */
  4297.  
  4298. bool
  4299. get_zone(name, inaddr, host)
  4300. input char *name;            /* name of zone to do zone xfer for */
  4301. input struct in_addr inaddr;        /* address of server to be queried */
  4302. input char *host;            /* name of server to be queried */
  4303. {
  4304.     querybuf query;
  4305.     querybuf answer;
  4306.     HEADER *bp;
  4307.     int ancount;
  4308.     int sock;
  4309.     struct sockaddr_in sin;
  4310.     register int n, i;
  4311.     int nrecords = 0;        /* number of records processed */
  4312.     int npackets = 0;        /* number of packets received */
  4313.  
  4314.     /* clear global counts */
  4315.     soacount = 0;            /* count of SOA records */
  4316.     zonecount = 0;            /* count of delegated zones */
  4317.     hostcount = 0;            /* count of host names */
  4318.  
  4319. /*
  4320.  * Construct query, and connect to the given server.
  4321.  */
  4322.     errno = 0;    /* reset before querying nameserver */
  4323.  
  4324.     n = res_mkquery(QUERY, name, queryclass, T_AXFR, (qbuf_t *)NULL, 0,
  4325.             (rrec_t *)NULL, (qbuf_t *)&query, sizeof(querybuf));
  4326.     if (n < 0)
  4327.     {
  4328.         if (debug)
  4329.             printf("%sres_mkquery failed\n", dbprefix);
  4330.         h_errno = NO_RECOVERY;
  4331.         return(FALSE);
  4332.     }
  4333.  
  4334.     if (debug)
  4335.     {
  4336.         printf("%sget_zone()\n", dbprefix);
  4337.         pr_query((qbuf_t *)&query, n, stdout);
  4338.     }
  4339.  
  4340.     /* setup destination address */
  4341.     bzero((char *)&sin, sizeof(sin));
  4342.  
  4343.     sin.sin_family = AF_INET;
  4344.     sin.sin_port = htons(NAMESERVER_PORT);
  4345.     sin.sin_addr = inaddr;
  4346.  
  4347.     sock = socket(AF_INET, SOCK_STREAM, 0);
  4348.     if (sock < 0)
  4349.     {
  4350.         _res_perror(&sin, host, "socket");
  4351.         h_errno = TRY_AGAIN;
  4352.         return(FALSE);
  4353.     }
  4354.  
  4355.     if (_res_connect(sock, &sin, sizeof(sin)) < 0)
  4356.     {
  4357.         if (verbose || debug)
  4358.             _res_perror(&sin, host, "connect");
  4359.         (void) close(sock);
  4360.         h_errno = TRY_AGAIN;
  4361.         return(FALSE);
  4362.     }
  4363.  
  4364.     if (verbose)
  4365.         printf("Asking zone transfer for %s ...\n", name);
  4366.  
  4367. /*
  4368.  * Send the query buffer.
  4369.  */
  4370.     if (_res_write(sock, &sin, host, (char *)&query, n) < 0)
  4371.     {
  4372.         (void) close(sock);
  4373.         h_errno = TRY_AGAIN;
  4374.         return(FALSE);
  4375.     }
  4376.  
  4377. /*
  4378.  * Process all incoming packets, usually one record in a separate packet.
  4379.  */
  4380.     while ((n = _res_read(sock, &sin, host, (char *)&answer, sizeof(querybuf))) != 0)
  4381.     {
  4382.         if (n < 0)
  4383.         {
  4384.             (void) close(sock);
  4385.             h_errno = TRY_AGAIN;
  4386.             return(FALSE);
  4387.         }
  4388.  
  4389.         errno = 0;    /* reset after we got an answer */
  4390.  
  4391.         if (n < HFIXEDSZ)
  4392.         {
  4393.             pr_error("answer length %s too short during %s for %s from %s",
  4394.                 itoa(n), pr_type(T_AXFR), name, host);
  4395.             (void) close(sock);
  4396.             h_errno = TRY_AGAIN;
  4397.             return(FALSE);
  4398.         }
  4399.  
  4400.         if (debug > 1)
  4401.         {
  4402.             printf("%sgot answer, %d bytes:\n", dbprefix, n);
  4403.             pr_query((qbuf_t *)&answer, querysize(n), stdout);
  4404.         }
  4405.  
  4406.     /*
  4407.      * Analyze the contents of the answer and check for errors.
  4408.      * An error can be expected only in the very first packet.
  4409.      * The query section should be empty except in the first packet.
  4410.      * Note the special error status codes for specific failures.
  4411.      */
  4412.         bp = (HEADER *)&answer;
  4413.         ancount = ntohs(bp->ancount);
  4414.  
  4415.         if (bp->rcode != NOERROR || ancount == 0)
  4416.         {
  4417.             if (verbose || debug)
  4418.                 print_status(&answer, n);
  4419.  
  4420.             switch (bp->rcode)
  4421.             {
  4422.                 case NXDOMAIN:
  4423.                 /* distinguish between authoritative or not */
  4424.                 h_errno = bp->aa ? HOST_NOT_FOUND : NO_HOST;
  4425.                 break;
  4426.  
  4427.                 case NOERROR:
  4428.                 /* distinguish between authoritative or not */
  4429.                 h_errno = bp->aa ? NO_DATA : NO_RREC;
  4430.                 break;
  4431.  
  4432.                 case REFUSED:
  4433.                 /* special status if zone transfer refused */
  4434.                 h_errno = QUERY_REFUSED;
  4435.                 break;
  4436.  
  4437.                 case SERVFAIL:
  4438.                 /* special status upon explicit failure */
  4439.                 h_errno = SERVER_FAILURE;
  4440.                 break;
  4441.  
  4442.                 default:
  4443.                 /* all other errors will cause a retry */
  4444.                 h_errno = TRY_AGAIN;
  4445.                 break;
  4446.             }
  4447.  
  4448.             if (npackets != 0)
  4449.                 pr_error("unexpected error during %s for %s from %s",
  4450.                     pr_type(T_AXFR), name, host);
  4451.  
  4452.             (void) close(sock);
  4453.             return(FALSE);
  4454.         }
  4455.  
  4456.         /* valid answer received, avoid buffer overrun */
  4457.         h_errno = 0;
  4458.         n = querysize(n);
  4459.  
  4460.     /*
  4461.      * The nameserver and additional info section should be empty.
  4462.      * There may be multiple answers in the answer section.
  4463.      */
  4464. #ifdef obsolete
  4465.         if (ancount > 1)
  4466.             pr_error("multiple answers during %s for %s from %s",
  4467.                 pr_type(T_AXFR), name, host);
  4468. #endif
  4469.         if (ntohs(bp->nscount) != 0)
  4470.             pr_error("nonzero nscount during %s for %s from %s",
  4471.                 pr_type(T_AXFR), name, host);
  4472.  
  4473.         if (ntohs(bp->arcount) != 0)
  4474.             pr_error("nonzero arcount during %s for %s from %s",
  4475.                 pr_type(T_AXFR), name, host);
  4476.  
  4477.     /*
  4478.      * Valid packet received. Print contents if appropriate.
  4479.      * Specific zone information will be saved by update_zone().
  4480.      */
  4481.         npackets += 1;
  4482.         nrecords += ancount;
  4483.  
  4484.         soaname = NULL, subname = NULL, adrname = NULL, address = 0;
  4485.         listhost = host;
  4486.  
  4487.         (void) print_info(&answer, n, name, T_AXFR, queryclass, FALSE);
  4488.  
  4489.     /*
  4490.      * Terminate upon the second SOA record for this zone.
  4491.      */
  4492.         if (soacount > 1)
  4493.             break;
  4494.     }
  4495.  
  4496. /*
  4497.  * End of zone transfer at second SOA record or zero length read.
  4498.  */
  4499.     (void) close(sock);
  4500.  
  4501. /*
  4502.  * Check for the anomaly that the whole transfer consisted of the
  4503.  * SOA records only. Could occur if we queried the victim of a lame
  4504.  * delegation which happened to have the SOA record present.
  4505.  */
  4506.     if (nrecords <= soacount)
  4507.     {
  4508.         pr_error("empty zone transfer for %s from %s",
  4509.             name, host);
  4510.         h_errno = NO_RREC;
  4511.         return(FALSE);
  4512.     }
  4513.  
  4514. /*
  4515.  * Do an extra check for delegated zones that also have an A record.
  4516.  * Those may have been defined in the child zone, and crept in the
  4517.  * parent zone, or may have been defined as glue records.
  4518.  * This is not necessarily an error, but the host count may be wrong.
  4519.  * Note that an A record for the current zone has been ignored above.
  4520.  */
  4521.     for (n = 0; n < zonecount; n++)
  4522.     {
  4523.         i = host_index(zonename[n], FALSE);
  4524. #ifdef obsolete
  4525.         for (i = 0; i < hostcount; i++)
  4526.             if (sameword(hostname(i), zonename[n]))
  4527.                 break;    /* found */
  4528. #endif
  4529.         if (i < hostcount)
  4530.             pr_warning("%s has both NS and A records within %s from %s",
  4531.                 zonename[n], name, host);
  4532.     }
  4533.  
  4534. /*
  4535.  * The zone transfer has been successful.
  4536.  */
  4537.     if (verbose)
  4538.     {
  4539.         printf("Transfer complete, %d record%s received for %s\n",
  4540.             nrecords, plural(nrecords), name);
  4541.         if (npackets != nrecords)
  4542.             printf("Transfer consisted of %d packet%s from %s\n",
  4543.                 npackets, plural(npackets), host);
  4544.     }
  4545.  
  4546.     return(TRUE);
  4547. }
  4548.  
  4549. /*
  4550. ** UPDATE_ZONE -- Save zone information during zone listings
  4551. ** ---------------------------------------------------------
  4552. **
  4553. **    Returns:
  4554. **        None.
  4555. **
  4556. **    Side effects:
  4557. **        Stores list of delegated zones found in zonename[],
  4558. **        and the count of delegated zones in ``zonecount''.
  4559. **        Stores list of host names found in hostname[],
  4560. **        and the count of host names in ``hostcount''.
  4561. **        Stores the count of SOA records in ``soacount''.
  4562. **
  4563. **    This routine is called by print_info() for each resource record.
  4564. */
  4565.  
  4566. void
  4567. update_zone(name)
  4568. input char *name;            /* name of zone to do zone xfer for */
  4569. {
  4570.     char *host = listhost;        /* contacted host for zone listings */
  4571.     register int i;
  4572.  
  4573. /*
  4574.  * Terminate upon the second SOA record for this zone.
  4575.  */
  4576.     if (soaname && sameword(soaname, name))
  4577.         soacount++;
  4578.  
  4579.     /* the nameserver balks on this one */
  4580.     else if (soaname && !sameword(soaname, name))
  4581.         pr_warning("extraneous SOA record for %s within %s from %s",
  4582.             soaname, name, host);
  4583.  
  4584. /*
  4585.  * Save encountered delegated zone name for recursive listing.
  4586.  */
  4587.     if (subname && indomain(subname, name, FALSE))
  4588.     {
  4589.         i = zone_index(subname, TRUE);
  4590. #ifdef obsolete
  4591.         for (i = 0; i < zonecount; i++)
  4592.             if (sameword(zonename[i], subname))
  4593.                 break;    /* duplicate */
  4594. #endif
  4595.         if (i >= zonecount)
  4596.         {
  4597.             zonename = newlist(zonename, zonecount+1, char *);
  4598.             zonename[zonecount] = newstr(subname);
  4599.             zonecount++;
  4600.         }
  4601.     }
  4602.  
  4603.     /* warn about strange delegated zones */
  4604.     else if (subname && !indomain(subname, name, TRUE))
  4605.         pr_warning("extraneous NS record for %s within %s from %s",
  4606.             subname, name, host);
  4607.  
  4608. /*
  4609.  * Save encountered name of A record for host name count.
  4610.  */
  4611.     if (adrname && indomain(adrname, name, FALSE) && !reverse)
  4612.     {
  4613.         i = host_index(adrname, TRUE);
  4614. #ifdef obsolete
  4615.         for (i = 0; i < hostcount; i++)
  4616.             if (sameword(hostname(i), adrname))
  4617.                 break;    /* duplicate */
  4618. #endif
  4619.         if (i >= hostcount)
  4620.         {
  4621.             if (hostcount >= maxhosts)
  4622.             {
  4623.                 maxhosts += MAXHOSTINCR;
  4624.                 hostlist = newlist(hostlist, maxhosts, host_data_t);
  4625.             }
  4626.             hostname(hostcount) = newstr(adrname);
  4627.             hostaddr(hostcount) = address;
  4628.             multaddr(hostcount) = FALSE;
  4629.             hostcount++;
  4630.         }
  4631.         else if (address != hostaddr(i))
  4632.             multaddr(i) = TRUE;
  4633.     }
  4634.  
  4635.     /* check for unauthoritative glue records */
  4636.     else if (adrname && !indomain(adrname, name, TRUE))
  4637.         pr_warning("extraneous glue record for %s within %s from %s",
  4638.             adrname, name, host);
  4639. }
  4640.  
  4641. /*
  4642. ** GET_MXREC -- Fetch MX records of a domain
  4643. ** -----------------------------------------
  4644. **
  4645. **    Returns:
  4646. **        TRUE if MX records were found.
  4647. **        FALSE otherwise.
  4648. */
  4649.  
  4650. bool
  4651. get_mxrec(name)
  4652. input char *name;            /* domain name to get mx for */
  4653. {
  4654.     querybuf answer;
  4655.     register int n;
  4656.  
  4657.     if (verbose)
  4658.         printf("Finding MX records for %s ...\n", name);
  4659.  
  4660.     n = get_info(&answer, name, T_MX, queryclass);
  4661.     if (n < 0)
  4662.         return(FALSE);
  4663.  
  4664.     (void) print_info(&answer, n, name, T_MX, queryclass, FALSE);
  4665.  
  4666.     return(TRUE);
  4667. }
  4668.  
  4669. /*
  4670. ** GET_PRIMARY -- Fetch name of primary nameserver for a zone
  4671. ** ----------------------------------------------------------
  4672. **
  4673. **    Returns:
  4674. **        Pointer to the name of the primary server, if found.
  4675. **        NULL if the server could not be determined.
  4676. */
  4677.  
  4678. char *
  4679. get_primary(name)
  4680. input char *name;            /* name of zone to get soa for */
  4681. {
  4682.     querybuf answer;
  4683.     register int n;
  4684.  
  4685.     if (verbose)
  4686.         printf("Finding primary nameserver for %s ...\n", name);
  4687.  
  4688.     n = get_info(&answer, name, T_SOA, queryclass);
  4689.     if (n < 0)
  4690.         return(NULL);
  4691.  
  4692.     if (verbose > 1)
  4693.         (void) print_info(&answer, n, name, T_SOA, queryclass, FALSE);
  4694.  
  4695.     soaname = NULL;
  4696.     (void) get_soainfo(&answer, n, name);
  4697.     if (soaname == NULL)
  4698.         return(NULL);
  4699.  
  4700.     return(soa.primary);
  4701. }
  4702.  
  4703. /*
  4704. ** CHECK_ZONE -- Fetch and analyze SOA record of a zone
  4705. ** ----------------------------------------------------
  4706. **
  4707. **    Returns:
  4708. **        TRUE if the SOA record was found at the given server.
  4709. **        FALSE otherwise.
  4710. **
  4711. **    Inputs:
  4712. **        The global variable ``server'' must contain the name
  4713. **        of the server that was queried.
  4714. */
  4715.  
  4716. bool
  4717. check_zone(name)
  4718. input char *name;            /* name of zone to get soa for */
  4719. {
  4720.     querybuf answer;
  4721.     register int n;
  4722.  
  4723.     if (verbose)
  4724.         printf("Checking SOA for %s at server %s ...\n", name, server);
  4725.     else if (authserver)
  4726.         printf("%-20s\tNS\t%s\n", name, server);
  4727.     else
  4728.         printf("%s\t(%s)\n", name, server);
  4729.  
  4730.     n = get_info(&answer, name, T_SOA, queryclass);
  4731.     if (n < 0)
  4732.         return(FALSE);
  4733.  
  4734.     if (verbose > 1)
  4735.         (void) print_info(&answer, n, name, T_SOA, queryclass, FALSE);
  4736.  
  4737.     soaname = NULL;
  4738.     (void) get_soainfo(&answer, n, name);
  4739.     if (soaname == NULL)
  4740.         return(FALSE);
  4741.  
  4742.     check_soa(&answer, name);
  4743.  
  4744.     return(TRUE);
  4745. }
  4746.  
  4747. /*
  4748. ** GET_SOAINFO -- Extract SOA data from nameserver answer buffer
  4749. ** -------------------------------------------------------------
  4750. **
  4751. **    Returns:
  4752. **        TRUE if the answer buffer was processed successfully.
  4753. **        FALSE otherwise.
  4754. **
  4755. **    Outputs:
  4756. **        The global struct ``soa'' is filled with the soa data.
  4757. **
  4758. **    Side effects:
  4759. **        Sets ``soaname'' if there is a valid SOA record.
  4760. **        This variable must have been cleared before calling
  4761. **        get_soainfo() and may be checked afterwards.
  4762. */
  4763.  
  4764. bool
  4765. get_soainfo(answerbuf, answerlen, name)
  4766. input querybuf *answerbuf;        /* location of answer buffer */
  4767. input int answerlen;            /* length of answer buffer */
  4768. input char *name;            /* name of zone to get soa for */
  4769. {
  4770.     HEADER *bp;
  4771.     int qdcount, ancount;
  4772.     u_char *msg, *eom;
  4773.     register u_char *cp;
  4774.  
  4775.     bp = (HEADER *)answerbuf;
  4776.     qdcount = ntohs(bp->qdcount);
  4777.     ancount = ntohs(bp->ancount);
  4778.  
  4779.     msg = (u_char *)answerbuf;
  4780.     eom = (u_char *)answerbuf + answerlen;
  4781.     cp  = (u_char *)answerbuf + HFIXEDSZ;
  4782.  
  4783.     if (qdcount > 0 && cp < eom)    /* should be exactly one record */
  4784.     {
  4785.         cp = skip_qrec(name, T_SOA, queryclass, cp, msg, eom);
  4786.         if (cp == NULL)
  4787.             return(FALSE);
  4788.         qdcount--;
  4789.     }
  4790.  
  4791.     if (qdcount)
  4792.     {
  4793.         pr_error("invalid qdcount after %s query for %s",
  4794.             pr_type(T_SOA), name);
  4795.         h_errno = NO_RECOVERY;
  4796.         return(FALSE);
  4797.     }
  4798.  
  4799. /*
  4800.  * Check answer section only.
  4801.  * Check that answers match the requested zone. Ignore other entries.
  4802.  * The nameserver section may contain the nameservers for the zone,
  4803.  * and the additional section their addresses, but not guaranteed.
  4804.  * Those sections are usually empty for authoritative answers.
  4805.  */
  4806.     while (ancount > 0 && cp < eom)
  4807.     {
  4808.         char rname[MAXDNAME+1];
  4809.         int type, class, ttl, dlen;
  4810.         u_char *eor;
  4811.         register int n;
  4812.  
  4813.         n = expand_name(name, T_NONE, cp, msg, eom, rname);
  4814.         if (n < 0)
  4815.             return(FALSE);
  4816.         cp += n;
  4817.  
  4818.         n = 3*INT16SZ + INT32SZ;
  4819.         if (check_size(rname, T_NONE, cp, msg, eom, n) < 0)
  4820.             return(FALSE);
  4821.  
  4822.         type = _getshort(cp);
  4823.         cp += INT16SZ;
  4824.  
  4825.         class = _getshort(cp);
  4826.         cp += INT16SZ;
  4827.  
  4828.         ttl = _getlong(cp);
  4829.         cp += INT32SZ;
  4830.  
  4831.         dlen = _getshort(cp);
  4832.         cp += INT16SZ;
  4833.  
  4834.         eor = cp + dlen;
  4835. #ifdef lint
  4836.         if (verbose)
  4837.             printf("%-20s\t%d\t%s\t%s\n",
  4838.                 rname, ttl, pr_class(class), pr_type(type));
  4839. #endif
  4840.         if ((type == T_SOA) && sameword(rname, name))
  4841.         {
  4842.             n = expand_name(rname, type, cp, msg, eom, soa.primary);
  4843.             if (n < 0)
  4844.                 return(FALSE);
  4845.             cp += n;
  4846.  
  4847.             n = expand_name(rname, type, cp, msg, eom, soa.hostmaster);
  4848.             if (n < 0)
  4849.                 return(FALSE);
  4850.             cp += n;
  4851.  
  4852.             n = 5*INT32SZ;
  4853.             if (check_size(rname, type, cp, msg, eor, n) < 0)
  4854.                 return(FALSE);
  4855.             soa.serial = _getlong(cp);
  4856.             cp += INT32SZ;
  4857.             soa.refresh = _getlong(cp);
  4858.             cp += INT32SZ;
  4859.             soa.retry = _getlong(cp);
  4860.             cp += INT32SZ;
  4861.             soa.expire = _getlong(cp);
  4862.             cp += INT32SZ;
  4863.             soa.defttl = _getlong(cp);
  4864.             cp += INT32SZ;
  4865.  
  4866.             /* valid complete soa record found */
  4867.             soaname = strcpy(soanamebuf, rname);
  4868.         }
  4869.         else
  4870.         {
  4871.             /* just ignore other records */
  4872.             cp += dlen;
  4873.         }
  4874.  
  4875.         if (cp != eor)
  4876.         {
  4877.             pr_error("size error in %s record for %s, off by %s",
  4878.                 pr_type(type), rname, itoa(cp - eor));
  4879.             h_errno = NO_RECOVERY;
  4880.             return(FALSE);
  4881.         }
  4882.  
  4883.         ancount--;
  4884.     }
  4885.  
  4886.     if (ancount)
  4887.     {
  4888.         pr_error("invalid ancount after %s query for %s",
  4889.             pr_type(T_SOA), name);
  4890.         h_errno = NO_RECOVERY;
  4891.         return(FALSE);
  4892.     }
  4893.  
  4894.     /* set proper status if no answers found */
  4895.     h_errno = (soaname != NULL) ? 0 : TRY_AGAIN;
  4896.     return(TRUE);
  4897. }
  4898.  
  4899. /*
  4900. ** CHECK_SOA -- Analyze retrieved SOA records of a zone
  4901. ** ----------------------------------------------------
  4902. **
  4903. **    Returns:
  4904. **        None.
  4905. **
  4906. **    Inputs:
  4907. **        The global variable ``server'' must contain the
  4908. **        name of the server that was queried.
  4909. **        The global struct ``soa'' must contain the soa data.
  4910. */
  4911.  
  4912. void
  4913. check_soa(answerbuf, name)
  4914. input querybuf *answerbuf;        /* location of answer buffer */
  4915. input char *name;            /* name of zone to check soa for */
  4916. {
  4917.     static char oldnamebuf[MAXDNAME+1];
  4918.     static char *oldname = NULL;    /* previous name of zone */
  4919.     static char *oldserver = NULL;    /* previous name of server */
  4920.     static soa_data_t oldsoa;    /* previous soa data */
  4921.     register int n;
  4922.     HEADER *bp;
  4923.  
  4924. /*
  4925.  * Print the various SOA fields in abbreviated form.
  4926.  * Values are actually unsigned, but we print them as signed integers,
  4927.  * apart from the serial which really becomes that big sometimes.
  4928.  * In the latter case we print a warning below.
  4929.  */
  4930.     printf("%s\t%s\t(%u %d %d %d %d)\n",
  4931.         soa.primary, soa.hostmaster, (unsigned)soa.serial,
  4932.         soa.refresh, soa.retry, soa.expire, soa.defttl);
  4933.  
  4934. /*
  4935.  * We are supposed to have queried an authoritative nameserver, and since
  4936.  * nameserver recursion has been turned off, answer must be authoritative.
  4937.  */
  4938.     bp = (HEADER *)answerbuf;
  4939.     if (!bp->aa)
  4940.     {
  4941.         if (authserver)
  4942.             pr_error("%s SOA record at %s is not authoritative",
  4943.                 name, server);
  4944.         else
  4945.             pr_warning("%s SOA record at %s is not authoritative",
  4946.                 name, server);
  4947.  
  4948.         if (authserver)
  4949.             errmsg("%s has lame delegation to %s",
  4950.                 name, server);
  4951.     }
  4952.  
  4953. /*
  4954.  * Check whether we are switching to a new zone.
  4955.  * The old name must have been saved in static storage.
  4956.  */
  4957.     if ((oldname != NULL) && !sameword(name, oldname))
  4958.         oldname = NULL;
  4959.  
  4960. /*
  4961.  * Make few timer consistency checks only for the first one in a series.
  4962.  * Compare the primary field against the list of authoritative servers.
  4963.  * Explicitly check the hostmaster field for illegal characters ('@').
  4964.  * Yell if the serial has the high bit set (not always intentional).
  4965.  */
  4966.     if (oldname == NULL)
  4967.     {
  4968.         for (n = 0; n < nservers; n++)
  4969.             if (sameword(soa.primary, nsname[n]))
  4970.                 break;    /* found */
  4971.  
  4972.         if ((n >= nservers) && authserver)
  4973.             pr_warning("%s SOA primary %s is not advertised via NS",
  4974.                 name, soa.primary);
  4975.  
  4976.         if (!valid_name(soa.primary, FALSE, FALSE, FALSE))
  4977.             pr_warning("%s SOA primary %s has illegal name",
  4978.                 name, soa.primary);
  4979.  
  4980.         if (!valid_name(soa.hostmaster, FALSE, TRUE, FALSE))
  4981.             pr_warning("%s SOA hostmaster %s has illegal mailbox",
  4982.                 name, soa.hostmaster);
  4983.  
  4984.         if (bitset(0x80000000, soa.serial))
  4985.             pr_warning("%s SOA serial has high bit set",
  4986.                 name);
  4987.  
  4988.         if (soa.retry > soa.refresh)
  4989.             pr_warning("%s SOA retry exceeds refresh",
  4990.                 name);
  4991.  
  4992.         if (soa.refresh + soa.retry > soa.expire)
  4993.             pr_warning("%s SOA refresh+retry exceeds expire",
  4994.                 name);
  4995.     }
  4996.  
  4997. /*
  4998.  * Compare various fields with those of the previous query, if any.
  4999.  * Different serial numbers may be present if secondaries have not yet
  5000.  * refreshed the data from the primary. Issue only a warning in that case.
  5001.  */
  5002.     if (oldname != NULL)
  5003.     {
  5004.         if (!sameword(soa.primary, oldsoa.primary))
  5005.             pr_error("%s and %s have different primary for %s",
  5006.                 server, oldserver, name);
  5007.  
  5008.         if (!sameword(soa.hostmaster, oldsoa.hostmaster))
  5009.             pr_error("%s and %s have different hostmaster for %s",
  5010.                 server, oldserver, name);
  5011.  
  5012.         if (soa.serial != oldsoa.serial)
  5013.             pr_warning("%s and %s have different serial for %s",
  5014.                 server, oldserver, name);
  5015.  
  5016.         if (soa.refresh != oldsoa.refresh)
  5017.             pr_error("%s and %s have different refresh for %s",
  5018.                 server, oldserver, name);
  5019.  
  5020.         if (soa.retry != oldsoa.retry)
  5021.             pr_error("%s and %s have different retry for %s",
  5022.                 server, oldserver, name);
  5023.  
  5024.         if (soa.expire != oldsoa.expire)
  5025.             pr_error("%s and %s have different expire for %s",
  5026.                 server, oldserver, name);
  5027.  
  5028.         if (soa.defttl != oldsoa.defttl)
  5029.             pr_error("%s and %s have different defttl for %s",
  5030.                 server, oldserver, name);
  5031.     }
  5032.  
  5033. /*
  5034.  * Save the current information.
  5035.  */
  5036.     oldname = strcpy(oldnamebuf, name);
  5037.     oldserver = server;
  5038.     oldsoa = soa;
  5039. }
  5040.  
  5041. /*
  5042. ** CHECK_DUPL -- Check global address list for duplicates
  5043. ** ------------------------------------------------------
  5044. **
  5045. **    Returns:
  5046. **        TRUE if the given host address already exists.
  5047. **        FALSE otherwise.
  5048. **
  5049. **    Side effects:
  5050. **        Adds the host address to the list if not present.
  5051. **
  5052. **    The information in this table is global, and is not cleared.
  5053. */
  5054.  
  5055. #define AHASHSIZE    0x2000
  5056. #define AHASHMASK    0x1fff
  5057.  
  5058. typedef struct addr_tab {
  5059.     ipaddr_t *addrlist;        /* global list of addresses */
  5060.     int addrcount;            /* count of global addresses */
  5061. } addr_tab_t;
  5062.  
  5063. addr_tab_t addrtab[AHASHSIZE];        /* hash list of global addresses */
  5064.  
  5065. bool
  5066. check_dupl(addr)
  5067. input ipaddr_t addr;            /* address of host to check */
  5068. {
  5069.      register int i;
  5070.     register addr_tab_t *s;
  5071.  
  5072.     s = &addrtab[ntohl(addr) & AHASHMASK];
  5073.  
  5074.     for (i = 0; i < s->addrcount; i++)
  5075.         if (s->addrlist[i] == addr)
  5076.             return(TRUE);    /* duplicate */
  5077.  
  5078.     s->addrlist = newlist(s->addrlist, s->addrcount+1, ipaddr_t);
  5079.     s->addrlist[s->addrcount] = addr;
  5080.     s->addrcount++;
  5081.     return(FALSE);
  5082. }
  5083.  
  5084. /*
  5085. ** CHECK_TTL -- Check list of records for different ttl values
  5086. ** -----------------------------------------------------------
  5087. **
  5088. **    Returns:
  5089. **        TRUE if the ttl value matches the first record
  5090. **        already listed with the same name/type/class.
  5091. **        FALSE only when the first discrepancy is found.
  5092. **
  5093. **    Side effects:
  5094. **        Adds the record data to the list if not present.
  5095. */
  5096.  
  5097. #define THASHSIZE    2003
  5098.  
  5099. typedef struct ttl_tab {
  5100.     struct ttl_tab *next;        /* next entry in chain */
  5101.     char *name;            /* name of resource record */
  5102.     int type;            /* resource record type */
  5103.     int class;            /* resource record class */
  5104.     int ttl;            /* time_to_live value */
  5105.     int count;            /* count of different ttl values */
  5106. } ttl_tab_t;
  5107.  
  5108. ttl_tab_t *ttltab[THASHSIZE];        /* hash list of record info */
  5109.  
  5110. bool
  5111. check_ttl(name, type, class, ttl)
  5112. input char *name;            /* resource record name */
  5113. input int type, class, ttl;        /* resource record fixed values */
  5114. {
  5115.     register ttl_tab_t *s;
  5116.     register ttl_tab_t **ps;
  5117.     register unsigned int hfunc;
  5118.     register char *p;
  5119.     register char c;
  5120.  
  5121. /*
  5122.  * Compute the hash function for this resource record.
  5123.  * Look it up in the appropriate hash chain.
  5124.  */
  5125.     for (hfunc = type, p = name; (c = *p) != '\0'; p++)
  5126.     {
  5127.         hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % THASHSIZE;
  5128.     }
  5129.  
  5130.     for (ps = &ttltab[hfunc]; (s = *ps) != NULL; ps = &s->next)
  5131.     {
  5132.         if (s->type != type || s->class != class)
  5133.             continue;
  5134.         if (sameword(s->name, name))
  5135.             break;
  5136.     }
  5137.  
  5138. /*
  5139.  * Allocate new entry if not found.
  5140.  */
  5141.     if (s == NULL)
  5142.     {
  5143.         /* ps = &ttltab[hfunc]; */
  5144.         s = newstruct(ttl_tab_t);
  5145.  
  5146.         /* initialize new entry */
  5147.         s->name = newstr(name);
  5148.         s->type = type;
  5149.         s->class = class;
  5150.         s->ttl = ttl;
  5151.         s->count = 0;
  5152.  
  5153.         /* link it in */
  5154.         s->next = *ps;
  5155.         *ps = s;
  5156.     }
  5157.  
  5158. /*
  5159.  * Check whether the ttl value matches the first recorded one.
  5160.  * If not, signal only the first discrepancy encountered, so
  5161.  * only one warning message will be printed.
  5162.  */
  5163.     if (s->ttl == ttl)
  5164.         return(TRUE);
  5165.  
  5166.     s->count += 1;
  5167.     return((s->count == 1) ? FALSE : TRUE);
  5168. }
  5169.  
  5170. /*
  5171. ** CLEAR_TTLTAB -- Clear resource record list for ttl checking
  5172. ** -----------------------------------------------------------
  5173. **
  5174. **    Returns:
  5175. **        None.
  5176. **
  5177. **    An entry on the hash list, and the host name in each
  5178. **    entry, have been allocated in dynamic memory.
  5179. **
  5180. **    The information in this table is on a per-zone basis.
  5181. **    It must be cleared before any subsequent zone transfers.
  5182. */
  5183.  
  5184. void
  5185. clear_ttltab()
  5186. {
  5187.     register int i;
  5188.     register ttl_tab_t *s, *t;
  5189.  
  5190.     for (i = 0; i < THASHSIZE; i++)
  5191.     {
  5192.         if (ttltab[i] != NULL)
  5193.         {
  5194.             /* free chain of entries */
  5195.             for (t = NULL, s = ttltab[i]; s != NULL; s = t)
  5196.             {
  5197.                 t = s->next;
  5198.                 xfree(s->name);
  5199.                 xfree(s);
  5200.             }
  5201.  
  5202.             /* reset hash chain */
  5203.             ttltab[i] = NULL;
  5204.         }
  5205.     }
  5206. }
  5207.  
  5208. /*
  5209. ** HOST_INDEX -- Check list of host names for name being present
  5210. ** -------------------------------------------------------------
  5211. **
  5212. **    Returns:
  5213. **        Index into hostname[] table, if found.
  5214. **        Current ``hostcount'' value, if not found.
  5215. **
  5216. **    Side effects:
  5217. **        May add an entry to the hash list if not present.
  5218. **
  5219. **    A linear search through the master table becomes very
  5220. **    costly for zones with more than a few thousand hosts.
  5221. **    Maintain a hash list with indexes into the master table.
  5222. **    Caller should update the master table after this call.
  5223. */
  5224.  
  5225. #define HHASHSIZE    2003
  5226.  
  5227. typedef struct host_tab {
  5228.     struct host_tab *next;        /* next entry in chain */
  5229.     int slot;            /* slot in host name table */
  5230. } host_tab_t;
  5231.  
  5232. host_tab_t *hosttab[HHASHSIZE];        /* hash list of host name info */
  5233.  
  5234. int
  5235. host_index(name, enter)
  5236. input char *name;            /* the host name to check */
  5237. input bool enter;            /* add to table if not found */
  5238. {
  5239.     register host_tab_t *s;
  5240.     register host_tab_t **ps;
  5241.     register unsigned int hfunc;
  5242.     register char *p;
  5243.     register char c;
  5244.  
  5245. /*
  5246.  * Compute the hash function for this host name.
  5247.  * Look it up in the appropriate hash chain.
  5248.  */
  5249.     for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
  5250.     {
  5251.         hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % HHASHSIZE;
  5252.     }
  5253.  
  5254.     for (ps = &hosttab[hfunc]; (s = *ps) != NULL; ps = &s->next)
  5255.     {
  5256.         if (s->slot >= hostcount)
  5257.             continue;
  5258.         if (sameword(hostname(s->slot), name))
  5259.             break;
  5260.     }
  5261.  
  5262. /*
  5263.  * Allocate new entry if not found.
  5264.  */
  5265.     if ((s == NULL) && enter)
  5266.     {
  5267.         /* ps = &hosttab[hfunc]; */
  5268.         s = newstruct(host_tab_t);
  5269.  
  5270.         /* initialize new entry */
  5271.         s->slot = hostcount;
  5272.  
  5273.         /* link it in */
  5274.         s->next = *ps;
  5275.         *ps = s;
  5276.     }
  5277.  
  5278.     return((s != NULL) ? s->slot : hostcount);
  5279. }
  5280.  
  5281. /*
  5282. ** CLEAR_HOSTTAB -- Clear hash list for host name checking
  5283. ** -------------------------------------------------------
  5284. **
  5285. **    Returns:
  5286. **        None.
  5287. **
  5288. **    A hash list entry has been allocated in dynamic memory.
  5289. **
  5290. **    The information in this table is on a per-zone basis.
  5291. **    It must be cleared before any subsequent zone transfers.
  5292. */
  5293.  
  5294. void
  5295. clear_hosttab()
  5296. {
  5297.     register int i;
  5298.     register host_tab_t *s, *t;
  5299.  
  5300.     for (i = 0; i < HHASHSIZE; i++)
  5301.     {
  5302.         if (hosttab[i] != NULL)
  5303.         {
  5304.             /* free chain of entries */
  5305.             for (t = NULL, s = hosttab[i]; s != NULL; s = t)
  5306.             {
  5307.                 t = s->next;
  5308.                 xfree(s);
  5309.             }
  5310.  
  5311.             /* reset hash chain */
  5312.             hosttab[i] = NULL;
  5313.         }
  5314.     }
  5315. }
  5316.  
  5317. /*
  5318. ** ZONE_INDEX -- Check list of zone names for name being present
  5319. ** -------------------------------------------------------------
  5320. **
  5321. **    Returns:
  5322. **        Index into zonename[] table, if found.
  5323. **        Current ``zonecount'' value, if not found.
  5324. **
  5325. **    Side effects:
  5326. **        May add an entry to the hash list if not present.
  5327. **
  5328. **    A linear search through the master table becomes very
  5329. **    costly for more than a few thousand delegated zones.
  5330. **    Maintain a hash list with indexes into the master table.
  5331. **    Caller should update the master table after this call.
  5332. */
  5333.  
  5334. #define ZHASHSIZE    2003
  5335.  
  5336. typedef struct zone_tab {
  5337.     struct zone_tab *next;        /* next entry in chain */
  5338.     int slot;            /* slot in zone name table */
  5339. } zone_tab_t;
  5340.  
  5341. zone_tab_t *zonetab[ZHASHSIZE];        /* hash list of zone name info */
  5342.  
  5343. int
  5344. zone_index(name, enter)
  5345. input char *name;            /* the zone name to check */
  5346. input bool enter;            /* add to table if not found */
  5347. {
  5348.     register zone_tab_t *s;
  5349.     register zone_tab_t **ps;
  5350.     register unsigned int hfunc;
  5351.     register char *p;
  5352.     register char c;
  5353.  
  5354. /*
  5355.  * Compute the hash function for this zone name.
  5356.  * Look it up in the appropriate hash chain.
  5357.  */
  5358.     for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
  5359.     {
  5360.         hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % ZHASHSIZE;
  5361.     }
  5362.  
  5363.     for (ps = &zonetab[hfunc]; (s = *ps) != NULL; ps = &s->next)
  5364.     {
  5365.         if (s->slot >= zonecount)
  5366.             continue;
  5367.         if (sameword(zonename[s->slot], name))
  5368.             break;
  5369.     }
  5370.  
  5371. /*
  5372.  * Allocate new entry if not found.
  5373.  */
  5374.     if ((s == NULL) && enter)
  5375.     {
  5376.         /* ps = &zonetab[hfunc]; */
  5377.         s = newstruct(zone_tab_t);
  5378.  
  5379.         /* initialize new entry */
  5380.         s->slot = zonecount;
  5381.  
  5382.         /* link it in */
  5383.         s->next = *ps;
  5384.         *ps = s;
  5385.     }
  5386.  
  5387.     return((s != NULL) ? s->slot : zonecount);
  5388. }
  5389.  
  5390. /*
  5391. ** CLEAR_ZONETAB -- Clear hash list for zone name checking
  5392. ** -------------------------------------------------------
  5393. **
  5394. **    Returns:
  5395. **        None.
  5396. **
  5397. **    A hash list entry has been allocated in dynamic memory.
  5398. **
  5399. **    The information in this table is on a per-zone basis.
  5400. **    It must be cleared before any subsequent zone transfers.
  5401. */
  5402.  
  5403. void
  5404. clear_zonetab()
  5405. {
  5406.     register int i;
  5407.     register zone_tab_t *s, *t;
  5408.  
  5409.     for (i = 0; i < ZHASHSIZE; i++)
  5410.     {
  5411.         if (zonetab[i] != NULL)
  5412.         {
  5413.             /* free chain of entries */
  5414.             for (t = NULL, s = zonetab[i]; s != NULL; s = t)
  5415.             {
  5416.                 t = s->next;
  5417.                 xfree(s);
  5418.             }
  5419.  
  5420.             /* reset hash chain */
  5421.             zonetab[i] = NULL;
  5422.         }
  5423.     }
  5424. }
  5425.  
  5426. /*
  5427. ** CHECK_CANON -- Check list of domain names for name being canonical
  5428. ** ------------------------------------------------------------------
  5429. **
  5430. **    Returns:
  5431. **        Nonzero if the name is definitely not canonical.
  5432. **        0 if it is canonical, or if it remains undecided.
  5433. **
  5434. **    Side effects:
  5435. **        Adds the domain name to the list if not present.
  5436. **
  5437. **    The information in this table is global, and is not cleared
  5438. **    (which may be necessary if the checking algorithm changes).
  5439. */
  5440.  
  5441. #define CHASHSIZE    2003
  5442.  
  5443. typedef struct canon_tab {
  5444.     struct canon_tab *next;        /* next entry in chain */
  5445.     char *name;            /* domain name */
  5446.     int status;            /* nonzero if not canonical */
  5447. } canon_tab_t;
  5448.  
  5449. canon_tab_t *canontab[CHASHSIZE];    /* hash list of domain name info */
  5450.  
  5451. int
  5452. check_canon(name)
  5453. input char *name;            /* the domain name to check */
  5454. {
  5455.     register canon_tab_t *s;
  5456.     register canon_tab_t **ps;
  5457.     register unsigned int hfunc;
  5458.     register char *p;
  5459.     register char c;
  5460.  
  5461. /*
  5462.  * Compute the hash function for this domain name.
  5463.  * Look it up in the appropriate hash chain.
  5464.  */
  5465.     for (hfunc = 0, p = name; (c = *p) != '\0'; p++)
  5466.     {
  5467.         hfunc = ((hfunc << 1) ^ (lowercase(c) & 0377)) % CHASHSIZE;
  5468.     }
  5469.  
  5470.     for (ps = &canontab[hfunc]; (s = *ps) != NULL; ps = &s->next)
  5471.     {
  5472.         if (sameword(s->name, name))
  5473.             break;
  5474.     }
  5475.  
  5476. /*
  5477.  * Allocate new entry if not found.
  5478.  * Only then is the actual check carried out.
  5479.  */
  5480.     if (s == NULL)
  5481.     {
  5482.         /* ps = &canontab[hfunc]; */
  5483.         s = newstruct(canon_tab_t);
  5484.  
  5485.         /* initialize new entry */
  5486.         s->name = newstr(name);
  5487.         s->status = canonical(name);
  5488.  
  5489.         /* link it in */
  5490.         s->next = *ps;
  5491.         *ps = s;
  5492.     }
  5493.  
  5494.     return(s->status);
  5495. }
  5496.  
  5497. /*
  5498. ** CHECK_ADDR -- Check whether reverse address mappings revert to host
  5499. ** -------------------------------------------------------------------
  5500. **
  5501. **    Returns:
  5502. **        TRUE if all addresses of host map back to host.
  5503. **        FALSE otherwise.
  5504. */
  5505.  
  5506. bool
  5507. check_addr(name)
  5508. input char *name;            /* host name to check addresses for */
  5509. {
  5510.     struct hostent *hp;
  5511.     register int i;
  5512.     struct in_addr inaddr[MAXADDRS];
  5513.     int naddress;
  5514.     char hnamebuf[MAXDNAME+1];
  5515.     char *hname;
  5516.     char inamebuf[MAXDNAME+1];
  5517.     char *iname;
  5518.     int matched;
  5519.  
  5520. /*
  5521.  * Look up the specified host to fetch its addresses.
  5522.  */
  5523.     hp = gethostbyname(name);
  5524.     if (hp == NULL)
  5525.     {
  5526.         ns_error(name, T_A, C_IN, server);
  5527.         return(FALSE);
  5528.     }
  5529.  
  5530.     hname = strncpy(hnamebuf, hp->h_name, MAXDNAME);
  5531.     hname[MAXDNAME] = '\0';
  5532.  
  5533.     for (i = 0; i < MAXADDRS && hp->h_addr_list[i]; i++)
  5534.         inaddr[i] = incopy(hp->h_addr_list[i]);
  5535.     naddress = i;
  5536.  
  5537.     if (verbose)
  5538.         printf("Found %d address%s for %s\n",
  5539.             naddress, plurale(naddress), hname);
  5540.  
  5541. /*
  5542.  * Map back the addresses found, and check whether they revert to host.
  5543.  */
  5544.     for (matched = 0, i = 0; i < naddress; i++)
  5545.     {
  5546.         iname = strcpy(inamebuf, inet_ntoa(inaddr[i]));
  5547.  
  5548.         if (verbose)
  5549.             printf("Checking %s address %s\n", hname, iname);
  5550.  
  5551.         hp = gethostbyaddr((char *)&inaddr[i], INADDRSZ, AF_INET);
  5552.         if (hp == NULL)
  5553.             ns_error(iname, T_PTR, C_IN, server);
  5554.         else if (!sameword(hp->h_name, hname))
  5555.             pr_warning("%s address %s maps to %s",
  5556.                 hname, iname, hp->h_name);
  5557.         else
  5558.             matched++;
  5559.     }
  5560.  
  5561.     return((matched == naddress) ? TRUE : FALSE);
  5562. }
  5563.  
  5564. /*
  5565. ** CHECK_NAME -- Check whether address belongs to host addresses
  5566. ** -------------------------------------------------------------
  5567. **
  5568. **    Returns:
  5569. **        TRUE if given address was found among host addresses.
  5570. **        FALSE otherwise.
  5571. */
  5572.  
  5573. bool
  5574. check_name(addr)
  5575. input ipaddr_t addr;            /* address of host to check */
  5576. {
  5577.     struct hostent *hp;
  5578.     register int i;
  5579.     struct in_addr inaddr;
  5580.     char hnamebuf[MAXDNAME+1];
  5581.     char *hname;
  5582.     char inamebuf[MAXDNAME+1];
  5583.     char *iname;
  5584.     int matched;
  5585.  
  5586. /*
  5587.  * Check whether the address is registered by fetching its host name.
  5588.  */
  5589.     inaddr.s_addr = addr;
  5590.     iname = strcpy(inamebuf, inet_ntoa(inaddr));
  5591.  
  5592.     hp = gethostbyaddr((char *)&inaddr, INADDRSZ, AF_INET);
  5593.     if (hp == NULL)
  5594.     {
  5595.         ns_error(iname, T_PTR, C_IN, server);
  5596.         return(FALSE);
  5597.     }
  5598.  
  5599.     hname = strncpy(hnamebuf, hp->h_name, MAXDNAME);
  5600.     hname[MAXDNAME] = '\0';
  5601.  
  5602.     if (verbose)
  5603.         printf("Address %s maps to %s\n", iname, hname);
  5604.  
  5605. /*
  5606.  * Lookup the host name found to fetch its addresses.
  5607.  */
  5608.     hp = gethostbyname(hname);
  5609.     if (hp == NULL)
  5610.     {
  5611.         ns_error(hname, T_A, C_IN, server);
  5612.         return(FALSE);
  5613.     }
  5614.  
  5615. /*
  5616.  * Verify whether the mapped host name is canonical.
  5617.  */
  5618.     if (!sameword(hp->h_name, hname))
  5619.         pr_warning("%s host %s is not canonical (%s)",
  5620.             iname, hname, hp->h_name);
  5621.  
  5622. /*
  5623.  * Check whether the given address is listed among the known addresses.
  5624.  */
  5625.     for (matched = 0, i = 0; hp->h_addr_list[i]; i++)
  5626.     {
  5627.         inaddr = incopy(hp->h_addr_list[i]);
  5628.  
  5629.         if (verbose)
  5630.             printf("Checking %s address %s\n",
  5631.                 hname, inet_ntoa(inaddr));
  5632.  
  5633.         if (inaddr.s_addr == addr)
  5634.             matched++;
  5635.     }
  5636.  
  5637.     if (!matched)
  5638.         pr_error("address %s does not belong to %s",
  5639.             iname, hname);
  5640.  
  5641.     return(matched ? TRUE : FALSE);
  5642. }
  5643.  
  5644. /*
  5645. ** GETH_BYNAME -- Wrapper for gethostbyname
  5646. ** ----------------------------------------
  5647. **
  5648. **    Returns:
  5649. **        Pointer to struct hostent if lookup was successful.
  5650. **        NULL otherwise.
  5651. **
  5652. **    Note. This routine works for fully qualified names only.
  5653. **    The entire special res_search() processing can be skipped.
  5654. */
  5655.  
  5656. struct hostent *
  5657. geth_byname(name)
  5658. input CONST char *name;            /* name to do forward lookup for */
  5659. {
  5660.     querybuf answer;
  5661.     struct hostent *hp;
  5662.     register int n;
  5663.  
  5664.     hp = gethostbyname(name);
  5665.     if (hp != NULL)
  5666.         return(hp);
  5667.  
  5668.     if (verbose > print_level)
  5669.         printf("Finding addresses for %s ...\n", name);
  5670.  
  5671.     n = get_info(&answer, name, T_A, C_IN);
  5672.     if (n < 0)
  5673.         return(NULL);
  5674.  
  5675.     if ((verbose > print_level + 1) && (print_level < 1))
  5676.         (void) print_info(&answer, n, name, T_A, C_IN, FALSE);
  5677.  
  5678.     hp = gethostbyname(name);
  5679.     return(hp);
  5680. }
  5681.  
  5682. /*
  5683. ** GETH_BYADDR -- Wrapper for gethostbyaddr
  5684. ** ----------------------------------------
  5685. **
  5686. **    Returns:
  5687. **        Pointer to struct hostent if lookup was successful.
  5688. **        NULL otherwise.
  5689. */
  5690.  
  5691. struct hostent *
  5692. geth_byaddr(addr, size, family)
  5693. input CONST char *addr;            /* address to do reverse mapping for */
  5694. input int size;                /* size of the address */
  5695. input int family;            /* address family */
  5696. {
  5697.     char addrbuf[4*4 + sizeof(ARPA_ROOT) + 1];
  5698.     char *name = addrbuf;
  5699.     u_char *a = (u_char *)addr;
  5700.     querybuf answer;
  5701.     struct hostent *hp;
  5702.     register int n;
  5703.  
  5704.     if (size != INADDRSZ || family != AF_INET)
  5705.     {
  5706.         hp = gethostbyaddr(addr, size, family);
  5707.         return(hp);
  5708.     }
  5709.  
  5710.     hp = gethostbyaddr(addr, size, family);
  5711.     if (hp != NULL)
  5712.         return(hp);
  5713.  
  5714.     /* construct absolute reverse name *without* trailing dot */
  5715.     (void) sprintf(addrbuf, "%u.%u.%u.%u.%s",
  5716.         a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
  5717.  
  5718.     if (verbose > print_level)
  5719.         printf("Finding reverse mapping for %s ...\n",
  5720.             inet_ntoa(incopy(addr)));
  5721.  
  5722.     n = get_info(&answer, name, T_PTR, C_IN);
  5723.     if (n < 0)
  5724.         return(NULL);
  5725.  
  5726.     if ((verbose > print_level + 1) && (print_level < 1))
  5727.         (void) print_info(&answer, n, name, T_PTR, C_IN, FALSE);
  5728.  
  5729.     hp = gethostbyaddr(addr, size, family);
  5730.     return(hp);
  5731. }
  5732.  
  5733. /*
  5734. ** PARSE_TYPE -- Decode rr type from input string
  5735. ** ----------------------------------------------
  5736. **
  5737. **    Returns:
  5738. **        Value of resource record type.
  5739. **        -1 if specified record name is invalid.
  5740. **
  5741. **    Note.    Several types are deprecated or obsolete, but recognized.
  5742. **        T_AXFR/T_IXFR is not allowed to be specified as query type.
  5743. */
  5744.  
  5745. int
  5746. parse_type(str)
  5747. input char *str;            /* input string with record type */
  5748. {
  5749.     register int type;
  5750.  
  5751.         /* standard types */
  5752.  
  5753.     if (sameword(str, "A"))        return(T_A);
  5754.     if (sameword(str, "NS"))    return(T_NS);
  5755.     if (sameword(str, "MD"))    return(T_MD);        /* obsolete */
  5756.     if (sameword(str, "MF"))    return(T_MF);        /* obsolete */
  5757.     if (sameword(str, "CNAME"))    return(T_CNAME);
  5758.     if (sameword(str, "SOA"))    return(T_SOA);
  5759.     if (sameword(str, "MB"))    return(T_MB);        /* deprecated */
  5760.     if (sameword(str, "MG"))    return(T_MG);        /* deprecated */
  5761.     if (sameword(str, "MR"))    return(T_MR);        /* deprecated */
  5762.     if (sameword(str, "NULL"))    return(T_NULL);        /* obsolete */
  5763.     if (sameword(str, "WKS"))    return(T_WKS);
  5764.     if (sameword(str, "PTR"))    return(T_PTR);
  5765.     if (sameword(str, "HINFO"))    return(T_HINFO);
  5766.     if (sameword(str, "MINFO"))    return(T_MINFO);    /* deprecated */
  5767.     if (sameword(str, "MX"))    return(T_MX);
  5768.     if (sameword(str, "TXT"))    return(T_TXT);
  5769.  
  5770.         /* new types */
  5771.  
  5772.     if (sameword(str, "RP"))    return(T_RP);
  5773.     if (sameword(str, "AFSDB"))    return(T_AFSDB);
  5774.     if (sameword(str, "X25"))    return(T_X25);
  5775.     if (sameword(str, "ISDN"))    return(T_ISDN);
  5776.     if (sameword(str, "RT"))    return(T_RT);
  5777.     if (sameword(str, "NSAP"))    return(T_NSAP);
  5778.     if (sameword(str, "NSAP-PTR"))    return(T_NSAPPTR);
  5779.     if (sameword(str, "SIG"))    return(T_SIG);
  5780.     if (sameword(str, "KEY"))    return(T_KEY);
  5781.     if (sameword(str, "PX"))    return(T_PX);
  5782.     if (sameword(str, "GPOS"))    return(T_GPOS);        /* withdrawn */
  5783.     if (sameword(str, "AAAA"))    return(T_AAAA);
  5784.     if (sameword(str, "LOC"))    return(T_LOC);
  5785.     if (sameword(str, "NXT"))    return(T_NXT);
  5786.     if (sameword(str, "EID"))    return(T_EID);
  5787.     if (sameword(str, "NIMLOC"))    return(T_NIMLOC);
  5788.     if (sameword(str, "SRV"))    return(T_SRV);
  5789.     if (sameword(str, "ATMA"))    return(T_ATMA);
  5790.     if (sameword(str, "NAPTR"))    return(T_NAPTR);
  5791.  
  5792.         /* nonstandard types */
  5793.  
  5794.     if (sameword(str, "UINFO"))    return(T_UINFO);
  5795.     if (sameword(str, "UID"))    return(T_UID);
  5796.     if (sameword(str, "GID"))    return(T_GID);
  5797.     if (sameword(str, "UNSPEC"))    return(T_UNSPEC);
  5798.  
  5799.         /* filters */
  5800.  
  5801.     if (sameword(str, "IXFR"))    return(-1);        /* illegal */
  5802.     if (sameword(str, "AXFR"))    return(-1);        /* illegal */
  5803.     if (sameword(str, "MAILB"))    return(T_MAILB);
  5804.     if (sameword(str, "MAILA"))    return(T_MAILA);    /* obsolete */
  5805.     if (sameword(str, "ANY"))    return(T_ANY);
  5806.     if (sameword(str, "*"))        return(T_ANY);
  5807.  
  5808.         /* unknown types */
  5809.  
  5810.     type = atoi(str);
  5811.     if (type >= T_FIRST && type <= T_LAST)
  5812.         return(type);
  5813.  
  5814.     return(-1);
  5815. }
  5816.  
  5817. /*
  5818. ** PARSE_CLASS -- Decode rr class from input string
  5819. ** ------------------------------------------------
  5820. **
  5821. **    Returns:
  5822. **        Value of resource class.
  5823. **        -1 if specified class name is invalid.
  5824. **
  5825. **    Note.    C_CSNET is obsolete, but recognized.
  5826. */
  5827.  
  5828. int
  5829. parse_class(str)
  5830. input char *str;            /* input string with resource class */
  5831. {
  5832.     register int class;
  5833.  
  5834.     if (sameword(str, "IN"))    return(C_IN);
  5835.     if (sameword(str, "INTERNET"))    return(C_IN);
  5836.     if (sameword(str, "CS"))    return(C_CSNET);    /* obsolete */
  5837.     if (sameword(str, "CSNET"))    return(C_CSNET);    /* obsolete */
  5838.     if (sameword(str, "CH"))    return(C_CHAOS);
  5839.     if (sameword(str, "CHAOS"))    return(C_CHAOS);
  5840.     if (sameword(str, "HS"))    return(C_HS);
  5841.     if (sameword(str, "HESIOD"))    return(C_HS);
  5842.  
  5843.     if (sameword(str, "ANY"))    return(C_ANY);
  5844.     if (sameword(str, "*"))        return(C_ANY);
  5845.  
  5846.     class = atoi(str);
  5847.     if (class > 0)
  5848.         return(class);
  5849.  
  5850.     return(-1);
  5851. }
  5852.  
  5853. /*
  5854. ** IN_ADDR_ARPA -- Convert dotted quad string to reverse in-addr.arpa
  5855. ** ------------------------------------------------------------------
  5856. **
  5857. **    Returns:
  5858. **        Pointer to appropriate reverse in-addr.arpa name
  5859. **        with trailing dot to force absolute domain name.
  5860. **        NULL in case of invalid dotted quad input string.
  5861. */
  5862.  
  5863. char *
  5864. in_addr_arpa(dottedquad)
  5865. input char *dottedquad;            /* input string with dotted quad */
  5866. {
  5867.     static char addrbuf[4*4 + sizeof(ARPA_ROOT) + 2];
  5868.     unsigned int a[4];
  5869.     register int n;
  5870.  
  5871.     n = sscanf(dottedquad, "%u.%u.%u.%u", &a[0], &a[1], &a[2], &a[3]);
  5872.     switch (n)
  5873.     {
  5874.         case 4:
  5875.         (void) sprintf(addrbuf, "%u.%u.%u.%u.%s.",
  5876.             a[3]&0xff, a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
  5877.         break;
  5878.  
  5879.         case 3:
  5880.         (void) sprintf(addrbuf, "%u.%u.%u.%s.",
  5881.             a[2]&0xff, a[1]&0xff, a[0]&0xff, ARPA_ROOT);
  5882.         break;
  5883.  
  5884.         case 2:
  5885.         (void) sprintf(addrbuf, "%u.%u.%s.",
  5886.             a[1]&0xff, a[0]&0xff, ARPA_ROOT);
  5887.         break;
  5888.  
  5889.         case 1:
  5890.         (void) sprintf(addrbuf, "%u.%s.",
  5891.             a[0]&0xff, ARPA_ROOT);
  5892.         break;
  5893.  
  5894.         default:
  5895.         return(NULL);
  5896.     }
  5897.  
  5898.     while (--n >= 0)
  5899.         if (a[n] > 255)
  5900.             return(NULL);
  5901.  
  5902.     return(addrbuf);
  5903. }
  5904.  
  5905. /*
  5906. ** NSAP_INT -- Convert dotted nsap address string to reverse nsap.int
  5907. ** ------------------------------------------------------------------
  5908. **
  5909. **    Returns:
  5910. **        Pointer to appropriate reverse nsap.int name
  5911. **        with trailing dot to force absolute domain name.
  5912. **        NULL in case of invalid nsap address input string.
  5913. */
  5914.  
  5915. char *
  5916. nsap_int(name)
  5917. input char *name;            /* input string with dotted nsap */
  5918. {
  5919.     static char addrbuf[4*MAXNSAP + sizeof(NSAP_ROOT) + 2];
  5920.     register int n;
  5921.     register int i;
  5922.  
  5923.     /* skip optional leading hex indicator */
  5924.     if (samehead(name, "0x"))
  5925.         name += 2;
  5926.  
  5927.     for (n = 0, i = strlength(name)-1; i >= 0; --i)
  5928.     {
  5929.         /* skip optional interspersed separators */
  5930.         if (name[i] == '.' || name[i] == '+' || name[i] == '/')
  5931.             continue;
  5932.  
  5933.         /* must consist of hex digits only */
  5934.         if (!is_xdigit(name[i]))
  5935.             return(NULL);
  5936.  
  5937.         /* but not too many */
  5938.         if (n >= 4*MAXNSAP)
  5939.             return(NULL);
  5940.  
  5941.         addrbuf[n++] = name[i];
  5942.         addrbuf[n++] = '.';
  5943.     }
  5944.  
  5945.     /* must have an even number of hex digits */ 
  5946.     if (n == 0 || (n % 4) != 0)
  5947.         return(NULL);
  5948.  
  5949.     (void) sprintf(&addrbuf[n], "%s.", NSAP_ROOT);
  5950.     return(addrbuf);
  5951. }
  5952.  
  5953. /*
  5954. ** PRINT_HOST -- Print host name and address of hostent struct
  5955. ** -----------------------------------------------------------
  5956. **
  5957. **    Returns:
  5958. **        None.
  5959. */
  5960.  
  5961. void
  5962. print_host(heading, hp)
  5963. input char *heading;            /* header string */
  5964. input struct hostent *hp;        /* location of hostent struct */
  5965. {
  5966.     register char **ap;
  5967.  
  5968.     printf("%s: %s", heading, hp->h_name);
  5969.  
  5970.     for (ap = hp->h_addr_list; ap && *ap; ap++)
  5971.     {
  5972.         if (ap == hp->h_addr_list)
  5973.             printf("\nAddress:");
  5974.  
  5975.         printf(" %s", inet_ntoa(incopy(*ap)));
  5976.     }
  5977.  
  5978.     for (ap = hp->h_aliases; ap && *ap && **ap; ap++)
  5979.     {
  5980.         if (ap == hp->h_aliases)
  5981.             printf("\nAliases:");
  5982.  
  5983.         printf(" %s", *ap);
  5984.     }
  5985.  
  5986.     printf("\n\n");
  5987. }
  5988.  
  5989. /*
  5990. ** SHOW_RES -- Show resolver database information
  5991. ** ----------------------------------------------
  5992. **
  5993. **    Returns:
  5994. **        None.
  5995. **
  5996. **    Inputs:
  5997. **        The resolver database _res is localized in the resolver.
  5998. */
  5999.  
  6000. void
  6001. show_res()
  6002. {
  6003.     register int i;
  6004.     register char **domain;
  6005.  
  6006. /*
  6007.  * The default domain is defined by the "domain" entry in /etc/resolv.conf
  6008.  * if not overridden by the environment variable "LOCALDOMAIN".
  6009.  * If still not defined, gethostname() may yield a fully qualified host name.
  6010.  */
  6011.     printf("Default domain:");
  6012.     if (_res.defdname[0] != '\0')
  6013.         printf(" %s", _res.defdname);
  6014.     printf("\n");
  6015.  
  6016. /*
  6017.  * The search domains are extracted from the default domain components,
  6018.  * but may be overridden by "search" directives in /etc/resolv.conf
  6019.  * since 4.8.3.
  6020.  */
  6021.     printf("Search domains:");
  6022.     for (domain = _res.dnsrch; *domain; domain++)
  6023.         printf(" %s", *domain);
  6024.     printf("\n");
  6025.  
  6026. /*
  6027.  * The routine res_send() will do _res.retry tries to contact each of the
  6028.  * _res.nscount nameserver addresses before giving up when using datagrams.
  6029.  * The first try will timeout after _res.retrans seconds. Each following
  6030.  * try will timeout after ((_res.retrans << try) / _res.nscount) seconds.
  6031.  * Note. When we contact an explicit server the addresses will be replaced
  6032.  * by the multiple addresses of the same server.
  6033.  * When doing a zone transfer _res.retrans is used for the connect timeout.
  6034.  */
  6035.     printf("Timeout per retry: %d secs\n", _res.retrans);
  6036.     printf("Number of retries: %d\n", _res.retry);
  6037.  
  6038.     printf("Number of addresses: %d\n", _res.nscount);
  6039.     for (i = 0; i < _res.nscount; i++)
  6040.         printf("%s\n", inet_ntoa(nslist(i).sin_addr));
  6041.  
  6042. /*
  6043.  * The resolver options are initialized by res_init() to contain the
  6044.  * defaults settings (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
  6045.  * The various options have the following meaning:
  6046.  *
  6047.  *    RES_INIT    set after res_init() has been called
  6048.  *    RES_DEBUG    let the resolver modules print debugging info
  6049.  *    RES_AAONLY    want authoritative answers only (not implemented)
  6050.  *    RES_USEVC    use tcp virtual circuit instead of udp datagrams
  6051.  *    RES_PRIMARY    use primary nameserver only (not implemented)
  6052.  *    RES_IGNTC    ignore datagram truncation; don't switch to tcp
  6053.  *    RES_RECURSE    forward query if answer not locally available
  6054.  *    RES_DEFNAMES    add default domain to queryname without dot
  6055.  *    RES_STAYOPEN    keep tcp socket open for subsequent queries
  6056.  *    RES_DNSRCH    append search domains even to queryname with dot
  6057.  */
  6058.     printf("Options set:");
  6059.     if (bitset(RES_INIT,      _res.options)) printf(" INIT");
  6060.     if (bitset(RES_DEBUG,     _res.options)) printf(" DEBUG");
  6061.     if (bitset(RES_AAONLY,    _res.options)) printf(" AAONLY");
  6062.     if (bitset(RES_USEVC,     _res.options)) printf(" USEVC");
  6063.     if (bitset(RES_PRIMARY,   _res.options)) printf(" PRIMARY");
  6064.     if (bitset(RES_IGNTC,     _res.options)) printf(" IGNTC");
  6065.     if (bitset(RES_RECURSE,   _res.options)) printf(" RECURSE");
  6066.     if (bitset(RES_DEFNAMES,  _res.options)) printf(" DEFNAMES");
  6067.     if (bitset(RES_STAYOPEN,  _res.options)) printf(" STAYOPEN");
  6068.     if (bitset(RES_DNSRCH,    _res.options)) printf(" DNSRCH");
  6069.     printf("\n");
  6070.  
  6071.     printf("Options clr:");
  6072.     if (!bitset(RES_INIT,     _res.options)) printf(" INIT");
  6073.     if (!bitset(RES_DEBUG,    _res.options)) printf(" DEBUG");
  6074.     if (!bitset(RES_AAONLY,   _res.options)) printf(" AAONLY");
  6075.     if (!bitset(RES_USEVC,    _res.options)) printf(" USEVC");
  6076.     if (!bitset(RES_PRIMARY,  _res.options)) printf(" PRIMARY");
  6077.     if (!bitset(RES_IGNTC,    _res.options)) printf(" IGNTC");
  6078.     if (!bitset(RES_RECURSE,  _res.options)) printf(" RECURSE");
  6079.     if (!bitset(RES_DEFNAMES, _res.options)) printf(" DEFNAMES");
  6080.     if (!bitset(RES_STAYOPEN, _res.options)) printf(" STAYOPEN");
  6081.     if (!bitset(RES_DNSRCH,   _res.options)) printf(" DNSRCH");
  6082.     printf("\n");
  6083.  
  6084. /*
  6085.  * The new BIND 4.9.3 has additional features which are not (yet) used.
  6086.  */
  6087.     printf("\n");
  6088. }
  6089.  
  6090. /*
  6091. ** PRINT_STATISTICS -- Print resource record statistics
  6092. ** ----------------------------------------------------
  6093. **
  6094. **    Returns:
  6095. **        None.
  6096. **
  6097. **    Inputs:
  6098. **        The record_stats[] counts have been updated by print_rrec().
  6099. */
  6100.  
  6101. void
  6102. print_statistics(name, filter, class)
  6103. input char *name;            /* name of zone we are listing */
  6104. input int filter;            /* type of records we want to see */
  6105. input int class;            /* class of records we want to see */
  6106. {
  6107.     register int type;
  6108.     int nrecords;
  6109.  
  6110.     for (type = T_FIRST; type <= T_LAST; type++)
  6111.     {
  6112.         nrecords = record_stats[type];
  6113.         if (nrecords > 0 || ((filter != T_ANY) && want_type(type, filter)))
  6114.         {
  6115.             printf("Found %4d %-5s record%-1s", nrecords,
  6116.                 pr_type(type), plural(nrecords));
  6117.  
  6118.             if (class != C_IN)
  6119.                 printf(" in class %s", pr_class(class));
  6120.  
  6121.             printf(" within %s\n", name);
  6122.         }
  6123.     }
  6124. }
  6125.  
  6126.  
  6127. /*
  6128. ** CLEAR_STATISTICS -- Clear resource record statistics
  6129. ** ----------------------------------------------------
  6130. **
  6131. **    Returns:
  6132. **        None.
  6133. */
  6134.  
  6135. void
  6136. clear_statistics()
  6137. {
  6138.     bzero((char *)record_stats, sizeof(record_stats));
  6139. }
  6140.  
  6141. /*
  6142. ** SHOW_TYPES -- Show resource record types wanted
  6143. ** -----------------------------------------------
  6144. **
  6145. **    Returns:
  6146. **        None.
  6147. */
  6148.  
  6149. void
  6150. show_types(name, filter, class)
  6151. input char *name;            /* name we want to query about */
  6152. input int filter;            /* type of records we want to see */
  6153. input int class;            /* class of records we want to see */
  6154. {
  6155.     register int type;
  6156.  
  6157.     if (filter >= T_NONE)
  6158.     {
  6159.         printf("Query about %s for record types", name);
  6160.  
  6161.         if (filter == T_ANY)
  6162.             printf(" %s", pr_type(T_ANY));
  6163.         else
  6164.             for (type = T_FIRST; type <= T_LAST; type++)
  6165.                 if (want_type(type, filter))
  6166.                     printf(" %s", pr_type(type));
  6167.  
  6168.         if (class != C_IN)
  6169.             printf(" in class %s", pr_class(class));
  6170.  
  6171.         printf("\n");
  6172.     }
  6173. }
  6174.  
  6175. /*
  6176. ** NS_ERROR -- Print error message from errno and h_errno
  6177. ** ------------------------------------------------------
  6178. **
  6179. **    Returns:
  6180. **        None.
  6181. **
  6182. ** If BIND res_send() fails, it will leave errno in either of the first
  6183. ** two following states when using datagrams. Note that this depends on
  6184. ** the proper handling of connected datagram sockets, which is usually
  6185. ** true if BSD >= 43 (see res_send.c for details; it may need a patch).
  6186. ** Note. If the 4.8 version succeeds, it may leave errno as EAFNOSUPPORT
  6187. ** if it has disconnected a previously connected datagram socket, since
  6188. ** the dummy address used to disconnect does not have a proper family set.
  6189. ** Always clear errno after getting a reply, or patch res_send().
  6190. ** Our private version of res_send() will leave also other error statuses.
  6191. */
  6192.  
  6193. void
  6194. ns_error(name, type, class, host) 
  6195. input char *name;            /* full name we queried about */
  6196. input int type;                /* record type we queried about */
  6197. input int class;            /* record class we queried about */
  6198. input char *host;            /* set if explicit server was used */
  6199. {
  6200.     static char *auth = "Authoritative answer";
  6201.  
  6202. /*
  6203.  * Print the message associated with the network related errno values.
  6204.  */
  6205.     switch (errno)
  6206.     {
  6207.         case ECONNREFUSED:
  6208.         /*
  6209.          * The contacted host does not have a nameserver running.
  6210.          * The standard res_send() also returns this if none of
  6211.          * the intended hosts could be reached via datagrams.
  6212.          */
  6213.         if (host != NULL)
  6214.             errmsg("Nameserver %s not running", host);
  6215.         else
  6216.             errmsg("Nameserver not running");
  6217.         break;
  6218.  
  6219.         case ETIMEDOUT:
  6220.         /*
  6221.          * The contacted server did not give any reply at all
  6222.          * within the specified time frame.
  6223.          */
  6224.         if (host != NULL)
  6225.             errmsg("Nameserver %s not responding", host);
  6226.         else
  6227.             errmsg("Nameserver not responding");
  6228.         break;
  6229.  
  6230.         case ENETDOWN:
  6231.         case ENETUNREACH:
  6232.         case EHOSTDOWN:
  6233.         case EHOSTUNREACH:
  6234.         /*
  6235.          * The host to be contacted or its network can not be reached.
  6236.          * Our private res_send() also returns this using datagrams.
  6237.          */
  6238.         if (host != NULL)
  6239.             errmsg("Nameserver %s not reachable", host);
  6240.         else
  6241.             errmsg("Nameserver not reachable");
  6242.         break;
  6243.     }
  6244.  
  6245. /*
  6246.  * Print the message associated with the particular nameserver error.
  6247.  */
  6248.     switch (h_errno)
  6249.     {
  6250.         case HOST_NOT_FOUND:
  6251.         /*
  6252.          * The specified name does definitely not exist at all.
  6253.          * In this case the answer is always authoritative.
  6254.          * Nameserver status: NXDOMAIN
  6255.          */
  6256.         if (class != C_IN)
  6257.             errmsg("%s does not exist in class %s (%s)",
  6258.                 name, pr_class(class), auth);
  6259.         else if (host != NULL)
  6260.             errmsg("%s does not exist at %s (%s)",
  6261.                 name, host, auth);
  6262.         else
  6263.             errmsg("%s does not exist (%s)",
  6264.                 name, auth);
  6265.         break;
  6266.  
  6267.         case NO_HOST:
  6268.         /*
  6269.          * The specified name does not exist, but the answer
  6270.          * was not authoritative, so it is still undecided.
  6271.          * Nameserver status: NXDOMAIN
  6272.          */
  6273.         if (class != C_IN)
  6274.             errmsg("%s does not exist in class %s, try again",
  6275.                 name, pr_class(class));
  6276.         else if (host != NULL)
  6277.             errmsg("%s does not exist at %s, try again",
  6278.                 name, host);
  6279.         else
  6280.             errmsg("%s does not exist, try again",
  6281.                 name);
  6282.         break;
  6283.  
  6284.         case NO_DATA:
  6285.         /*
  6286.          * The name is valid, but the specified type does not exist.
  6287.          * This status is here returned only in case authoritative.
  6288.          * Nameserver status: NOERROR
  6289.          */
  6290.         if (class != C_IN)
  6291.             errmsg("%s has no %s record in class %s (%s)",
  6292.                 name, pr_type(type), pr_class(class), auth);
  6293.         else if (host != NULL)
  6294.             errmsg("%s has no %s record at %s (%s)",
  6295.                 name, pr_type(type), host, auth);
  6296.         else
  6297.             errmsg("%s has no %s record (%s)",
  6298.                 name, pr_type(type), auth);
  6299.         break;
  6300.  
  6301.         case NO_RREC:
  6302.         /*
  6303.          * The specified type does not exist, but we don't know whether
  6304.          * the name is valid or not. The answer was not authoritative.
  6305.          * Perhaps recursion was off, and no data was cached locally.
  6306.          * Nameserver status: NOERROR
  6307.          */
  6308.         if (class != C_IN)
  6309.             errmsg("%s %s record in class %s currently not present",
  6310.                 name, pr_type(type), pr_class(class));
  6311.         else if (host != NULL)
  6312.             errmsg("%s %s record currently not present at %s",
  6313.                 name, pr_type(type), host);
  6314.         else
  6315.             errmsg("%s %s record currently not present",
  6316.                 name, pr_type(type));
  6317.         break;
  6318.  
  6319.         case TRY_AGAIN:
  6320.         /*
  6321.          * Some intermediate failure, e.g. connect timeout,
  6322.          * or some local operating system transient errors.
  6323.          * General failure to reach any appropriate servers.
  6324.          * The status SERVFAIL now yields a separate error code.
  6325.          * Nameserver status: (SERVFAIL)
  6326.          */
  6327.         if (class != C_IN)
  6328.             errmsg("%s %s record in class %s not found, try again",
  6329.                 name, pr_type(type), pr_class(class));
  6330.         else if (host != NULL)
  6331.             errmsg("%s %s record not found at %s, try again",
  6332.                 name, pr_type(type), host);
  6333.         else
  6334.             errmsg("%s %s record not found, try again",
  6335.                 name, pr_type(type));
  6336.         break;
  6337.  
  6338.         case SERVER_FAILURE:
  6339.         /*
  6340.          * Explicit server failure status. This will be returned upon
  6341.          * some internal server errors, forwarding failures, or when
  6342.          * the server is not authoritative for a specific class.
  6343.          * Also if the zone data has expired at a secondary server.
  6344.          * Nameserver status: SERVFAIL
  6345.          */
  6346.         if (class != C_IN)
  6347.             errmsg("%s %s record in class %s not found, server failure",
  6348.                 name, pr_type(type), pr_class(class));
  6349.         else if (host != NULL)
  6350.             errmsg("%s %s record not found at %s, server failure",
  6351.                 name, pr_type(type), host);
  6352.         else
  6353.             errmsg("%s %s record not found, server failure",
  6354.                 name, pr_type(type));
  6355.         break;
  6356.  
  6357.         case NO_RECOVERY:
  6358.         /*
  6359.          * Some irrecoverable format error, or server refusal.
  6360.          * The status REFUSED now yields a separate error code.
  6361.          * Nameserver status: (REFUSED) FORMERR NOTIMP NOCHANGE
  6362.          */
  6363.         if (class != C_IN)
  6364.             errmsg("%s %s record in class %s not found, no recovery",
  6365.                 name, pr_type(type), pr_class(class));
  6366.         else if (host != NULL)
  6367.             errmsg("%s %s record not found at %s, no recovery",
  6368.                 name, pr_type(type), host);
  6369.         else
  6370.             errmsg("%s %s record not found, no recovery",
  6371.                 name, pr_type(type));
  6372.         break;
  6373.  
  6374.         case QUERY_REFUSED:
  6375.         /*
  6376.          * The server explicitly refused to answer the query.
  6377.          * Servers can be configured to disallow zone transfers.
  6378.          * Nameserver status: REFUSED
  6379.          */
  6380.         if (class != C_IN)
  6381.             errmsg("%s %s record in class %s query refused",
  6382.                 name, pr_type(type), pr_class(class));
  6383.         else if (host != NULL)
  6384.             errmsg("%s %s record query refused by %s",
  6385.                 name, pr_type(type), host);
  6386.         else
  6387.             errmsg("%s %s record query refused",
  6388.                 name, pr_type(type));
  6389.         break;
  6390.  
  6391.         default:
  6392.         /*
  6393.          * Unknown cause for server failure.
  6394.          */
  6395.         if (class != C_IN)
  6396.             errmsg("%s %s record in class %s not found",
  6397.                 name, pr_type(type), pr_class(class));
  6398.         else if (host != NULL)
  6399.             errmsg("%s %s record not found at %s",
  6400.                 name, pr_type(type), host);
  6401.         else
  6402.             errmsg("%s %s record not found",
  6403.                 name, pr_type(type));
  6404.         break;
  6405.     }
  6406. }
  6407.  
  6408. /*
  6409. ** DECODE_ERROR -- Convert nameserver error code to error message
  6410. ** --------------------------------------------------------------
  6411. **
  6412. **    Returns:
  6413. **        Pointer to appropriate error message.
  6414. */
  6415.  
  6416. char *
  6417. decode_error(rcode)
  6418. input int rcode;            /* error code from bp->rcode */
  6419. {
  6420.     switch (rcode)
  6421.     {
  6422.         case NOERROR:     return("no error");
  6423.         case FORMERR:    return("format error");
  6424.         case SERVFAIL:    return("server failure");
  6425.         case NXDOMAIN:    return("non-existent domain");
  6426.         case NOTIMP:    return("not implemented");
  6427.         case REFUSED:    return("query refused");
  6428.         case NOCHANGE:    return("no change");
  6429.     }
  6430.  
  6431.     return("unknown error");
  6432. }
  6433.  
  6434. /*
  6435. ** PRINT_STATUS -- Print result status after nameserver query
  6436. ** ----------------------------------------------------------
  6437. **
  6438. **    Returns:
  6439. **        None.
  6440. **
  6441. **    Conditions:
  6442. **        The size of the answer buffer must have been
  6443. **        checked before to be of sufficient length,
  6444. **        i.e. to contain at least the buffer header.
  6445. */
  6446.  
  6447. void
  6448. print_status(answerbuf, answerlen)
  6449. input querybuf *answerbuf;        /* location of answer buffer */
  6450. input int answerlen;            /* length of answer buffer */
  6451. {
  6452.     HEADER *bp;
  6453.     int ancount;
  6454.     bool failed;
  6455.  
  6456.     bp = (HEADER *)answerbuf;
  6457.     ancount = ntohs(bp->ancount);
  6458.     failed = (bp->rcode != NOERROR || ancount == 0);
  6459.  
  6460.     printf("%s", verbose ? "" : dbprefix);
  6461.  
  6462.     printf("Query %s", failed ? "failed" : "done");
  6463.  
  6464.     if (bp->tc || (answerlen > PACKETSZ))
  6465.         printf(", %d byte%s", answerlen, plural(answerlen));
  6466.  
  6467.     if (bp->tc)
  6468.     {
  6469.         if (answerlen > sizeof(querybuf))
  6470.             printf(" (truncated to %d)", sizeof(querybuf));
  6471.         else
  6472.             printf(" (truncated)");
  6473.     }
  6474.  
  6475.     printf(", %d answer%s", ancount, plural(ancount));
  6476.  
  6477.     printf(", %s", bp->aa ? "authoritative " : "");
  6478.  
  6479.     printf("status: %s\n", decode_error((int)bp->rcode));
  6480. }
  6481.  
  6482. /*
  6483. ** PR_ERROR -- Print error message about encountered inconsistencies
  6484. ** -----------------------------------------------------------------
  6485. **
  6486. **    We are supposed to have an error condition which is fatal
  6487. **    for normal continuation, and the message is always printed.
  6488. **
  6489. **    Returns:
  6490. **        None.
  6491. **
  6492. **    Side effects:
  6493. **        Increments the global error count.
  6494. */
  6495.  
  6496. void /*VARARGS1*/
  6497. pr_error(fmt, a, b, c, d)
  6498. input char *fmt;            /* format of message */
  6499. input char *a, *b, *c, *d;        /* optional arguments */
  6500. {
  6501.     (void) fprintf(stderr, " *** ");
  6502.     (void) fprintf(stderr, fmt, a, b, c, d);
  6503.     (void) fprintf(stderr, "\n");
  6504.  
  6505.     /* flag an error */
  6506.     errorcount++;
  6507. }
  6508.  
  6509.  
  6510. /*
  6511. ** PR_WARNING -- Print warning message about encountered inconsistencies
  6512. ** ---------------------------------------------------------------------
  6513. **
  6514. **    We are supposed to have an error condition which is non-fatal
  6515. **    for normal continuation, and the message is suppressed in case
  6516. **    quiet mode has been selected.
  6517. **
  6518. **    Returns:
  6519. **        None.
  6520. */
  6521.  
  6522. void /*VARARGS1*/
  6523. pr_warning(fmt, a, b, c, d)
  6524. input char *fmt;            /* format of message */
  6525. input char *a, *b, *c, *d;        /* optional arguments */
  6526. {
  6527.     if (!quiet)
  6528.     {
  6529.         (void) fprintf(stderr, " !!! ");
  6530.         (void) fprintf(stderr, fmt, a, b, c, d);
  6531.         (void) fprintf(stderr, "\n");
  6532.     }
  6533. }
  6534.  
  6535. /*
  6536. ** WANT_TYPE -- Indicate whether the rr type matches the desired filter
  6537. ** --------------------------------------------------------------------
  6538. **
  6539. **    Returns:
  6540. **        TRUE if the resource record type matches the filter.
  6541. **        FALSE otherwise.
  6542. **
  6543. **    In regular mode, the querytype is used to formulate the query,
  6544. **    and the filter is set to T_ANY to filter out any response.
  6545. **    In listmode, we get everything, so the filter is set to the
  6546. **    querytype to filter out the proper responses.
  6547. **    Note that T_NONE is the default querytype in listmode.
  6548. */
  6549.  
  6550. bool
  6551. want_type(type, filter)
  6552. input int type;                /* resource record type */
  6553. input int filter;            /* type of records we want to see */
  6554. {
  6555.     if (type == filter)
  6556.         return(TRUE);
  6557.  
  6558.     if (filter == T_ANY)
  6559.         return(TRUE);
  6560.  
  6561.     if (filter == T_NONE &&
  6562.        (type == T_A || type == T_NS || type == T_PTR))
  6563.         return(TRUE);
  6564.  
  6565.     if (filter == T_MAILB &&
  6566.        (type == T_MB || type == T_MR || type == T_MG || type == T_MINFO))
  6567.         return(TRUE);
  6568.  
  6569.     if (filter == T_MAILA &&
  6570.        (type == T_MD || type == T_MF))
  6571.         return(TRUE);
  6572.  
  6573.     return(FALSE);
  6574. }
  6575.  
  6576. /*
  6577. ** WANT_CLASS -- Indicate whether the rr class matches the desired filter
  6578. ** ----------------------------------------------------------------------
  6579. **
  6580. **    Returns:
  6581. **        TRUE if the resource record class matches the filter.
  6582. **        FALSE otherwise.
  6583. **
  6584. **    In regular mode, the queryclass is used to formulate the query,
  6585. **    and the filter is set to C_ANY to filter out any response.
  6586. **    In listmode, we get everything, so the filter is set to the
  6587. **    queryclass to filter out the proper responses.
  6588. **    Note that C_IN is the default queryclass in listmode.
  6589. */
  6590.  
  6591. bool
  6592. want_class(class, filter)
  6593. input int class;            /* resource record class */
  6594. input int filter;            /* class of records we want to see */
  6595. {
  6596.     if (class == filter)
  6597.         return(TRUE);
  6598.  
  6599.     if (filter == C_ANY)
  6600.         return(TRUE);
  6601.  
  6602.     return(FALSE);
  6603. }
  6604.  
  6605. /*
  6606. ** INDOMAIN -- Check whether a name belongs to a zone
  6607. ** --------------------------------------------------
  6608. **
  6609. **    Returns:
  6610. **        TRUE if the given name lies anywhere in the zone, or
  6611. **        if the given name is the same as the zone and may be so.
  6612. **        FALSE otherwise.
  6613. */
  6614.  
  6615. bool
  6616. indomain(name, domain, equal)
  6617. input char *name;            /* the name under consideration */
  6618. input char *domain;            /* the name of the zone */
  6619. input bool equal;            /* set if name may be same as zone */
  6620. {
  6621.     register char *dot;
  6622.  
  6623.     if (sameword(name, domain))
  6624.         return(equal);
  6625.  
  6626.     if (sameword(domain, "."))
  6627.         return(TRUE);
  6628.  
  6629.     dot = index(name, '.');
  6630.     while (dot != NULL)
  6631.     {
  6632.         if (!is_quoted(dot, name))
  6633.         {
  6634.             if (sameword(dot+1, domain))
  6635.                 return(TRUE);
  6636.         }
  6637.  
  6638.         dot = index(dot+1, '.');
  6639.     }
  6640.  
  6641.     return(FALSE);
  6642. }
  6643.  
  6644. /*
  6645. ** SAMEDOMAIN -- Check whether a name belongs to a zone
  6646. ** ----------------------------------------------------
  6647. **
  6648. **    Returns:
  6649. **        TRUE if the given name lies directly in the zone, or
  6650. **        if the given name is the same as the zone and may be so.
  6651. **        FALSE otherwise.
  6652. */
  6653.  
  6654. bool
  6655. samedomain(name, domain, equal)
  6656. input char *name;            /* the name under consideration */
  6657. input char *domain;            /* the name of the zone */
  6658. input bool equal;            /* set if name may be same as zone */
  6659. {
  6660.     register char *dot;
  6661.  
  6662.     if (sameword(name, domain))
  6663.         return(equal);
  6664.  
  6665.     dot = index(name, '.');
  6666.     while (dot != NULL)
  6667.     {
  6668.         if (!is_quoted(dot, name))
  6669.         {
  6670.             if (sameword(dot+1, domain))
  6671.                 return(TRUE);
  6672.  
  6673.             return(FALSE);
  6674.         }
  6675.  
  6676.         dot = index(dot+1, '.');
  6677.     }
  6678.  
  6679.     if (sameword(domain, "."))
  6680.         return(TRUE);
  6681.  
  6682.     return(FALSE);
  6683. }
  6684.  
  6685. /*
  6686. ** GLUERECORD -- Check whether a name is a glue record
  6687. ** ---------------------------------------------------
  6688. **
  6689. **    Returns:
  6690. **        TRUE is this is a glue record.
  6691. **        FALSE otherwise.
  6692. **
  6693. **    The name is supposed to be the name of an address record.
  6694. **    If it lies directly in the given zone, it is considered
  6695. **    an ordinary host within that zone, and not a glue record.
  6696. **    If it does not belong to the given zone at all, is it
  6697. **    here considered to be a glue record.
  6698. **    If it lies in the given zone, but not directly, it is
  6699. **    considered a glue record if it belongs to any of the known
  6700. **    delegated zones of the given zone.
  6701. **    In the root zone itself are no hosts, only glue records.
  6702. */
  6703.  
  6704. bool
  6705. gluerecord(name, domain, zone, nzones)
  6706. input char *name;            /* the name under consideration */
  6707. input char *domain;            /* name of zone being processed */
  6708. input char *zone[];            /* list of known delegated zones */
  6709. input int nzones;            /* number of known delegated zones */
  6710. {
  6711.     register int n;
  6712.  
  6713.     if (sameword(domain, "."))
  6714.         return(TRUE);
  6715.  
  6716.     if (samedomain(name, domain, TRUE))
  6717.         return(FALSE);
  6718.  
  6719.     if (!indomain(name, domain, TRUE))
  6720.         return(TRUE);
  6721.  
  6722.     for (n = 0; n < nzones; n++)
  6723.         if (indomain(name, zone[n], TRUE))
  6724.             return(TRUE);
  6725.  
  6726.     return(FALSE);
  6727. }
  6728.  
  6729. /*
  6730. ** MATCHLABELS -- Determine number of matching domain name labels
  6731. ** --------------------------------------------------------------
  6732. **
  6733. **    Returns:
  6734. **        Number of shared trailing components in both names.
  6735. **
  6736. **    Note. This routine is currently used only to compare nameserver
  6737. **    names in the RHS of NS records, so there is no need to check
  6738. **    for embedded quoted dots.
  6739. */
  6740.  
  6741. int
  6742. matchlabels(name, domain)
  6743. input char *name;            /* domain name to check */
  6744. input char *domain;            /* domain name to compare against */
  6745. {
  6746.     register int i, j;
  6747.     int matched = 0;
  6748.  
  6749.     i = strlength(name);
  6750.     j = strlength(domain);
  6751.  
  6752.     while (--i >= 0 && --j >= 0)
  6753.     {
  6754.         if (lowercase(name[i]) != lowercase(domain[j]))
  6755.             break;
  6756.         if (domain[j] == '.')
  6757.             matched++;
  6758.         else if (j == 0 && (i == 0 || name[i-1] == '.'))
  6759.             matched++;
  6760.     }
  6761.  
  6762.     return(matched);
  6763. }
  6764.  
  6765. /*
  6766. ** PR_DOMAIN -- Convert domain name according to printing options
  6767. ** --------------------------------------------------------------
  6768. **
  6769. **    Returns:
  6770. **        Pointer to new domain name, if conversion was done.
  6771. **        Pointer to original name, if no conversion necessary.
  6772. */
  6773.  
  6774. char *
  6775. pr_domain(name, listing)
  6776. input char *name;            /* domain name to be printed */
  6777. input bool listing;            /* set if this is a zone listing */
  6778. {
  6779.     char *newname;            /* converted domain name */
  6780.  
  6781. /*
  6782.  * Print reverse nsap.int name in forward notation, unless prohibited.
  6783.  */
  6784.     if (revnsap && !dotprint)
  6785.     {
  6786.         newname = pr_nsap(name);
  6787.         if (newname != name)
  6788.             return(newname);
  6789.     }
  6790.  
  6791. /*
  6792.  * Print domain names with trailing dot if necessary.
  6793.  */
  6794.     if (listing || dotprint)
  6795.     {
  6796.         newname = pr_dotname(name);
  6797.         if (newname != name)
  6798.             return(newname);
  6799.     }
  6800.  
  6801. /*
  6802.  * No conversion was required, use original name.
  6803.  */
  6804.     return(name);
  6805. }
  6806.  
  6807. /*
  6808. ** PR_DOTNAME -- Return domain name with trailing dot
  6809. ** --------------------------------------------------
  6810. **
  6811. **    Returns:
  6812. **        Pointer to new domain name, if dot was added.
  6813. **        Pointer to original name, if dot was already present.
  6814. */
  6815.  
  6816. char *
  6817. pr_dotname(name)
  6818. input char *name;            /* domain name to append to */
  6819. {
  6820.     static char buf[MAXDNAME+2];    /* buffer to store new domain name */
  6821.     register int n;
  6822.  
  6823.     n = strlength(name);
  6824.     if (n > 0 && name[n-1] == '.')
  6825.         return(name);
  6826.  
  6827.     if (n > MAXDNAME)
  6828.         n = MAXDNAME;
  6829.  
  6830. #ifdef obsolete
  6831.     (void) sprintf(buf, "%.*s.", MAXDNAME, name);
  6832. #endif
  6833.     bcopy(name, buf, n);
  6834.     buf[n] = '.';
  6835.     buf[n+1] = '\0';
  6836.     return(buf);
  6837. }
  6838.  
  6839. /*
  6840. ** PR_NSAP -- Convert reverse nsap.int to dotted forward notation
  6841. ** --------------------------------------------------------------
  6842. **
  6843. **    Returns:
  6844. **        Pointer to new dotted nsap, if converted.
  6845. **        Pointer to original name otherwise.
  6846. */
  6847.  
  6848. char *
  6849. pr_nsap(name)
  6850. input char *name;            /* potential reverse nsap.int name */
  6851. {
  6852.     static char buf[3*MAXNSAP+1];
  6853.     register char *p;
  6854.     register int n;
  6855.     register int i;
  6856.  
  6857.     /* must begin with single hex digits separated by dots */
  6858.     for (i = 0; is_xdigit(name[i]) && name[i+1] == '.'; i += 2)
  6859.         continue;
  6860.  
  6861.     /* must have an even number of hex digits */ 
  6862.     if (i == 0 || (i % 4) != 0)
  6863.         return(name);
  6864.  
  6865.     /* but not too many */
  6866.     if (i > 4*MAXNSAP)
  6867.         return(name);
  6868.  
  6869.     /* must end in the appropriate root domain */
  6870.     if (!sameword(&name[i], NSAP_ROOT))
  6871.         return(name);
  6872.  
  6873.     for (p = buf, n = 0; i >= 4; i -= 4, n++)
  6874.     {
  6875.         *p++ = name[i-2];
  6876.         *p++ = name[i-4];
  6877.  
  6878.         /* add dots for readability */
  6879.         if ((n % 2) == 0 && (i - 4) > 0)
  6880.             *p++ = '.';
  6881.     }
  6882.     *p = '\0';
  6883.  
  6884.     return(buf);
  6885. }
  6886.  
  6887. /*
  6888. ** PR_TYPE -- Return name of resource record type
  6889. ** ----------------------------------------------
  6890. **
  6891. **    Returns:
  6892. **        Pointer to name of resource record type.
  6893. **
  6894. **    Note.    All possible (even obsolete) types are recognized.
  6895. */
  6896.  
  6897. char *
  6898. pr_type(type)
  6899. input int type;                /* resource record type */
  6900. {
  6901.     static char buf[30];        /* sufficient for 64-bit values */
  6902.  
  6903.     switch (type)
  6904.     {
  6905.         /* standard types */
  6906.  
  6907.         case T_A:       return("A");    /* internet address */
  6908.         case T_NS:      return("NS");    /* authoritative server */
  6909.         case T_MD:      return("MD");    /* mail destination */
  6910.         case T_MF:      return("MF");    /* mail forwarder */
  6911.         case T_CNAME:   return("CNAME");    /* canonical name */
  6912.         case T_SOA:     return("SOA");    /* start of auth zone */
  6913.         case T_MB:      return("MB");    /* mailbox domain name */
  6914.         case T_MG:      return("MG");    /* mail group member */
  6915.         case T_MR:      return("MR");    /* mail rename name */
  6916.         case T_NULL:    return("NULL");    /* null resource record */
  6917.         case T_WKS:     return("WKS");    /* well known service */
  6918.         case T_PTR:     return("PTR");    /* domain name pointer */
  6919.         case T_HINFO:   return("HINFO");    /* host information */
  6920.         case T_MINFO:   return("MINFO");    /* mailbox information */
  6921.         case T_MX:      return("MX");    /* mail routing info */
  6922.         case T_TXT:     return("TXT");    /* descriptive text */
  6923.  
  6924.         /* new types */
  6925.  
  6926.         case T_RP:      return("RP");    /* responsible person */
  6927.         case T_AFSDB:   return("AFSDB");    /* afs database location */
  6928.         case T_X25:     return("X25");    /* x25 address */
  6929.         case T_ISDN:    return("ISDN");    /* isdn address */
  6930.         case T_RT:      return("RT");    /* route through host */
  6931.         case T_NSAP:    return("NSAP");    /* nsap address */
  6932.         case T_NSAPPTR: return("NSAP-PTR");    /* nsap pointer */
  6933.         case T_SIG:     return("SIG");    /* security signature */
  6934.         case T_KEY:     return("KEY");    /* security key */
  6935.         case T_PX:      return("PX");    /* rfc822 - x400 mapping */
  6936.         case T_GPOS:    return("GPOS");    /* geographical position */
  6937.         case T_AAAA:    return("AAAA");    /* ip v6 address */
  6938.         case T_LOC:     return("LOC");    /* geographical location */
  6939.         case T_NXT:     return("NXT");    /* next valid name */
  6940.         case T_EID:     return("EID");    /* endpoint identifier */
  6941.         case T_NIMLOC:  return("NIMLOC");    /* nimrod locator */
  6942.         case T_SRV:     return("SRV");    /* service info */
  6943.         case T_ATMA:    return("ATMA");    /* atm address */
  6944.         case T_NAPTR:   return("NAPTR");    /* naming authority urn */
  6945.  
  6946.         /* nonstandard types */
  6947.  
  6948.         case T_UINFO:   return("UINFO");    /* user information */
  6949.         case T_UID:     return("UID");    /* user ident */
  6950.         case T_GID:     return("GID");    /* group ident */
  6951.         case T_UNSPEC:  return("UNSPEC");    /* unspecified binary data */
  6952.  
  6953.         /* filters */
  6954.  
  6955.         case T_IXFR:    return("IXFR");    /* incremental zone transfer */
  6956.         case T_AXFR:    return("AXFR");    /* zone transfer */
  6957.         case T_MAILB:   return("MAILB");    /* matches MB/MR/MG/MINFO */
  6958.         case T_MAILA:   return("MAILA");    /* matches MD/MF */
  6959.         case T_ANY:     return("ANY");    /* matches any type */
  6960.  
  6961.         case T_NONE:    return("resource");    /* not yet determined */
  6962.     }
  6963.  
  6964.     /* unknown type */
  6965.     (void) sprintf(buf, "%d", type);
  6966.     return(buf);
  6967. }
  6968.  
  6969. /*
  6970. ** PR_CLASS -- Return name of resource record class
  6971. ** ------------------------------------------------
  6972. **
  6973. **    Returns:
  6974. **        Pointer to name of resource record class.
  6975. */
  6976.  
  6977. char *
  6978. pr_class(class)
  6979. input int class;            /* resource record class */
  6980. {
  6981.     static char buf[30];        /* sufficient for 64-bit values */
  6982.  
  6983.     switch (class)
  6984.     {
  6985.         case C_IN:      return("IN");    /* internet */
  6986.         case C_CSNET:   return("CS");    /* csnet */
  6987.         case C_CHAOS:   return("CH");    /* chaosnet */
  6988.         case C_HS:      return("HS");    /* hesiod */
  6989.         case C_ANY:     return("ANY");    /* any class */
  6990.     }
  6991.  
  6992.     /* unknown class */
  6993.     (void) sprintf(buf, "%d", class);
  6994.     return(buf);
  6995. }
  6996.  
  6997. /*
  6998. ** EXPAND_NAME -- Expand compressed domain name in a resource record
  6999. ** -----------------------------------------------------------------
  7000. **
  7001. **    Returns:
  7002. **        Number of bytes advanced in answer buffer.
  7003. **        -1 if there was a format error.
  7004. **
  7005. **    It is assumed that the specified buffer is of a fixed size
  7006. **    MAXDNAME+1 that should be sufficient to store the data.
  7007. */
  7008.  
  7009. int
  7010. expand_name(name, type, cp, msg, eom, namebuf)
  7011. input char *name;            /* name of resource record */
  7012. input int type;                /* type of resource record */
  7013. input u_char *cp;            /* current position in answer buf */
  7014. input u_char *msg, *eom;        /* begin and end of answer buf */
  7015. output char *namebuf;            /* location of buf to expand name in */
  7016. {
  7017.     register int n;
  7018.  
  7019.     n = dn_expand(msg, eom, cp, (nbuf_t *)namebuf, MAXDNAME);
  7020.     if (n < 0)
  7021.     {
  7022.         pr_error("expand error in %s record for %s, offset %s",
  7023.             pr_type(type), name, itoa(cp - msg));
  7024.         h_errno = NO_RECOVERY;
  7025.         return(-1);
  7026.     }
  7027.  
  7028.     /* should not be necessary, but who knows */
  7029.     namebuf[MAXDNAME] = '\0';
  7030.  
  7031.     /* change root to single dot */
  7032.     if (namebuf[0] == '\0')
  7033.     {
  7034.         namebuf[0] = '.';
  7035.         namebuf[1] = '\0';
  7036.     }
  7037.  
  7038.     return(n);
  7039. }
  7040.  
  7041. /*
  7042. ** CHECK_SIZE -- Check whether resource record is of sufficient length
  7043. ** -------------------------------------------------------------------
  7044. **
  7045. **    Returns:
  7046. **        Requested size if current record is long enough.
  7047. **        -1 if current record does not have this many bytes.
  7048. **
  7049. **    Note that HINFO records are very often incomplete since only
  7050. **    one of the two data fields has been filled in and the second
  7051. **    field is missing. So we generate only a warning message.
  7052. */
  7053.  
  7054. int
  7055. check_size(name, type, cp, msg, eor, size)
  7056. input char *name;            /* name of resource record */
  7057. input int type;                /* type of resource record */
  7058. input u_char *cp;            /* current position in answer buf */
  7059. input u_char *msg;            /* begin of answer buf */
  7060. input u_char *eor;            /* predicted position of next record */
  7061. input int size;                /* required record size remaining */
  7062. {
  7063.     if (cp + size > eor)
  7064.     {
  7065.         if (type != T_HINFO)
  7066.             pr_error("incomplete %s record for %s, offset %s",
  7067.                 pr_type(type), name, itoa(cp - msg));
  7068.         else
  7069.             pr_warning("incomplete %s record for %s",
  7070.                 pr_type(type), name);
  7071.         h_errno = NO_RECOVERY;
  7072.         return(-1);
  7073.     }
  7074.  
  7075.     return(size);
  7076. }
  7077.  
  7078. /*
  7079. ** VALID_NAME -- Check whether domain name contains invalid characters
  7080. ** -------------------------------------------------------------------
  7081. **
  7082. **    Returns:
  7083. **        TRUE if the name is valid.
  7084. **        FALSE otherwise.
  7085. **
  7086. **    The total size of a compound name should not exceed MAXDNAME.
  7087. **    We assume that this is true. Its individual components between
  7088. **    dots should not be longer than 64. This is not checked here.
  7089. **
  7090. **    Only alphanumeric characters and dash '-' may be used (dash
  7091. **    only in the middle). We only check the individual characters.
  7092. **    Strictly speaking, this restriction is only for ``host names''.
  7093. **    The underscore is illegal, at least not recommended, but is
  7094. **    so abundant that it requires special processing.
  7095. **
  7096. **    If the domain name represents a mailbox specification, the
  7097. **    first label up to the first (unquoted) dot is the local part
  7098. **    of a mail address, which should adhere to the RFC 822 specs.
  7099. **    This first dot takes the place of the RFC 822 '@' sign.
  7100. **
  7101. **    The label '*' can in principle be used anywhere to indicate
  7102. **    wildcarding. It is valid only in the LHS resource record name,
  7103. **    in definitions in zone files only as the first component.
  7104. **    Used primarily in wildcard MX record definitions.
  7105. **
  7106. **    Note. This routine is much too liberal.
  7107. */
  7108.  
  7109. char *specials = ".()<>@,;:\\\"[]";    /* RFC 822 specials */
  7110.  
  7111. bool
  7112. valid_name(name, wildcard, localpart, underscore)
  7113. input char *name;            /* domain name to check */
  7114. input bool wildcard;            /* set if wildcard is allowed */
  7115. input bool localpart;            /* set if this is a mailbox spec */
  7116. input bool underscore;            /* set if underscores are allowed */
  7117. {
  7118.     bool backslash = FALSE;
  7119.     bool quoting = FALSE;
  7120.     register char *p;
  7121.     register char c;
  7122.  
  7123.     for (p = name; (c = *p) != '\0'; p++)
  7124.     {
  7125.         /* special check for local part in mailbox */
  7126.         if (localpart)
  7127.         {
  7128.             if (backslash)
  7129.                 backslash = FALSE;    /* escape this char */
  7130.             else if (c == '\\')
  7131.                 backslash = TRUE;    /* escape next char */
  7132.             else if (c == '"')
  7133.                 quoting = !quoting;    /* start/stop quoting */
  7134.             else if (quoting)
  7135.                 continue;        /* allow quoted chars */
  7136.             else if (c == '.')
  7137.                 localpart = FALSE;    /* instead of '@' */
  7138.             else if (c == '@')
  7139.                 return(FALSE);        /* should be '.' */
  7140.             else if (in_string(specials, c))
  7141.                 return(FALSE);        /* must be escaped */
  7142.             else if (is_space(c))
  7143.                 return(FALSE);        /* must be escaped */
  7144.             continue;
  7145.         }
  7146.  
  7147.         /* basic character set */
  7148.         if (is_alnum(c) || (c == '-'))
  7149.             continue;
  7150.  
  7151.         /* start of a new component */
  7152.         if (c == '.')
  7153.             continue;
  7154.  
  7155.         /* allow '*' for use in wildcard names */
  7156.         if ((c == '*') && (p == name && p[1] == '.') && wildcard)
  7157.             continue;
  7158.  
  7159.         /* ignore underscore in certain circumstances */
  7160.         if ((c == '_') && underscore && !illegal)
  7161.             continue;
  7162.  
  7163.         /* silently allowed widespread exceptions */
  7164.         if (illegal && in_string(illegal, c))
  7165.             continue;
  7166.  
  7167.         return(FALSE);
  7168.     }
  7169.  
  7170.     /* must be beyond the local part in a mailbox */
  7171.     if (localpart)
  7172.         return(FALSE);
  7173.  
  7174.     return(TRUE);
  7175. }
  7176.  
  7177. /* 
  7178. ** CANONICAL -- Check whether domain name is a canonical host name
  7179. ** ---------------------------------------------------------------
  7180. **
  7181. **    Returns:
  7182. **        Nonzero if the name is definitely not canonical.
  7183. **        0 if it is canonical, or if it remains undecided.
  7184. */
  7185.  
  7186. int
  7187. canonical(name)
  7188. input char *name;            /* the domain name to check */
  7189. {
  7190.     struct hostent *hp;
  7191.     int status;
  7192.     int save_errno;
  7193.     int save_herrno;
  7194.     
  7195. /*
  7196.  * Preserve state when querying, to avoid clobbering current values.
  7197.  */
  7198.     save_errno = errno;
  7199.     save_herrno = h_errno;
  7200.  
  7201.     hp = geth_byname(name);
  7202.     status = h_errno;
  7203.  
  7204.     errno = save_errno;
  7205.     h_errno = save_herrno;
  7206.  
  7207. /*
  7208.  * Indicate negative result only after definitive lookup failures.
  7209.  */
  7210.     if (hp == NULL)
  7211.     {
  7212.         /* authoritative denial -- not existing or no A record */
  7213.         if (status == NO_DATA || status == HOST_NOT_FOUND)
  7214.             return(status);
  7215.  
  7216.         /* nameserver failure -- still undecided, assume ok */
  7217.         return(0);
  7218.     }
  7219.  
  7220. /*
  7221.  * The given name exists and there is an associated A record.
  7222.  * The name of this A record should be the name we queried about.
  7223.  * If this is not the case we probably supplied a CNAME.
  7224.  */
  7225.     status = sameword(hp->h_name, name) ? 0 : HOST_NOT_CANON;
  7226.     return(status);
  7227. }
  7228.  
  7229. /* 
  7230. ** MAPREVERSE -- Check whether address maps back to given domain
  7231. ** -------------------------------------------------------------
  7232. **
  7233. **    Returns:
  7234. **        NULL if address could definitively not be mapped.
  7235. **        Given name if the address maps back properly, or
  7236. **        in case of transient nameserver failures.
  7237. **        Reverse name if it differs from the given name.
  7238. */
  7239.  
  7240. char *
  7241. mapreverse(name, inaddr)
  7242. input char *name;            /* domain name of A record */
  7243. input struct in_addr inaddr;        /* address of A record to check */
  7244. {
  7245.     struct hostent *hp;
  7246.     int status;
  7247.     int save_errno;
  7248.     int save_herrno;
  7249.     
  7250. /*
  7251.  * Preserve state when querying, to avoid clobbering current values.
  7252.  */
  7253.     save_errno = errno;
  7254.     save_herrno = h_errno;
  7255.  
  7256.     hp = geth_byaddr((char *)&inaddr, INADDRSZ, AF_INET);
  7257.     status = h_errno;
  7258.  
  7259.     errno = save_errno;
  7260.     h_errno = save_herrno;
  7261.  
  7262. /*
  7263.  * Indicate negative result only after definitive lookup failures.
  7264.  */
  7265.     if (hp == NULL)
  7266.     {
  7267.         /* authoritative denial -- not existing or no PTR record */
  7268.         if (status == NO_DATA || status == HOST_NOT_FOUND)
  7269.             return(NULL);
  7270.  
  7271.         /* nameserver failure -- still undecided, assume ok */
  7272.         return(name);
  7273.     }
  7274.  
  7275. /*
  7276.  * Indicate whether the reverse mapping yields the given name.
  7277.  */
  7278.     return(sameword(hp->h_name, name) ? name : hp->h_name);
  7279. }
  7280.  
  7281. /* 
  7282. ** COMPARE_NAME -- Compare two names wrt alphabetical order
  7283. ** --------------------------------------------------------
  7284. **
  7285. **    Returns:
  7286. **        Value of case-insensitive comparison.
  7287. */
  7288.  
  7289. int
  7290. compare_name(a, b)
  7291. input const ptr_t *a;            /* first name */
  7292. input const ptr_t *b;            /* second name */
  7293. {
  7294.     return(strcasecmp(*(char **)a, *(char **)b));
  7295. }
  7296.  
  7297. /*
  7298. ** XALLOC -- Allocate or reallocate additional memory
  7299. ** --------------------------------------------------
  7300. **
  7301. **    Returns:
  7302. **        Pointer to (re)allocated buffer space.
  7303. **        Aborts if the requested memory could not be obtained.
  7304. */
  7305.  
  7306. ptr_t *
  7307. xalloc(buf, size)
  7308. register ptr_t *buf;            /* current start of buffer space */
  7309. input siz_t size;            /* number of bytes to allocate */
  7310. {
  7311.     if (buf == NULL)
  7312.         buf = malloc(size);
  7313.     else
  7314.         buf = realloc(buf, size);
  7315.  
  7316.     if (buf == NULL)
  7317.     {
  7318.         errmsg("Out of memory");
  7319.         exit(EX_OSERR);
  7320.     }
  7321.  
  7322.     return(buf);
  7323. }
  7324.  
  7325. /*
  7326. ** ITOA -- Convert value to decimal integer ascii string
  7327. ** -----------------------------------------------------
  7328. **
  7329. **    Returns:
  7330. **        Pointer to string.
  7331. */
  7332.  
  7333. char *
  7334. itoa(n)
  7335. input int n;                /* value to convert */
  7336. {
  7337.     static char buf[30];        /* sufficient for 64-bit values */
  7338.  
  7339.     (void) sprintf(buf, "%d", n);
  7340.     return(buf);
  7341. }
  7342.  
  7343. /*
  7344. ** UTOA -- Convert value to unsigned decimal ascii string
  7345. ** ------------------------------------------------------
  7346. **
  7347. **    Returns:
  7348. **        Pointer to string.
  7349. */
  7350.  
  7351. char *
  7352. utoa(n)
  7353. input int n;                /* value to convert */
  7354. {
  7355.     static char buf[30];        /* sufficient for 64-bit values */
  7356.  
  7357.     (void) sprintf(buf, "%u", (unsigned)n);
  7358.     return(buf);
  7359. }
  7360.  
  7361. /*
  7362. ** XTOA -- Convert value to hexadecimal ascii string
  7363. ** -------------------------------------------------
  7364. **
  7365. **    Returns:
  7366. **        Pointer to string.
  7367. */
  7368.  
  7369. char *
  7370. xtoa(n)
  7371. input int n;                /* value to convert */
  7372. {
  7373.     static char buf[17];        /* sufficient for 64-bit values */
  7374.  
  7375.     (void) sprintf(buf, "%X", (unsigned)n);
  7376.     return(buf);
  7377. }
  7378.  
  7379. /*
  7380. ** STOA -- Extract partial ascii string, escape if necessary
  7381. ** ---------------------------------------------------------
  7382. **
  7383. **    Returns:
  7384. **        Pointer to string.
  7385. */
  7386.  
  7387. char *
  7388. stoa(cp, size, escape)
  7389. input u_char *cp;            /* current position in answer buf */
  7390. input int size;                /* number of bytes to extract */
  7391. input bool escape;            /* escape special characters if set */
  7392. {
  7393.     static char buf[2*MAXDLEN+1];
  7394.     register char *p;
  7395.     register char c;
  7396.     register int i;
  7397.  
  7398.     if (size > MAXDLEN)
  7399.         size = MAXDLEN;
  7400.  
  7401. #ifdef obsolete
  7402.     if (size > 0)
  7403.         (void) sprintf(buf, "%.*s", size, (char *)cp);
  7404.     else
  7405.         (void) sprintf(buf, "%s", "");
  7406. #endif
  7407.  
  7408.     for (p = buf, i = 0; i < size; i++)
  7409.     {
  7410.         c = *cp++;
  7411.         if (escape && (c == '\n' || c == '\\' || c == '"'))
  7412.             *p++ = '\\';
  7413.         *p++ = c;
  7414.     }
  7415.     *p = '\0';
  7416.  
  7417.     return(buf);
  7418. }
  7419.  
  7420. /*
  7421. ** BASE_NTOA -- Convert binary data to base64 ascii
  7422. ** ------------------------------------------------
  7423. **
  7424. **    Returns:
  7425. **        Pointer to string.
  7426. **
  7427. **    This routine is used to convert encoded keys and signatures
  7428. **    in T_KEY and T_SIG resource records.
  7429. */
  7430.  
  7431. char b64tab[] =
  7432. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  7433.  
  7434. char *
  7435. base_ntoa(cp, size)
  7436. input u_char *cp;            /* current position in answer buf */
  7437. input int size;                /* number of bytes to extract */
  7438. {
  7439.     static char buf[MAXB64SIZE+1];
  7440.     register char *p;
  7441.     int c1, c2, c3, c4;
  7442.  
  7443.     if (size > MAXMD5SIZE)
  7444.         size = MAXMD5SIZE;
  7445.  
  7446.     for (p = buf; size > 2; cp += 3, size -= 3)
  7447.     {
  7448.         c1 = (((int)cp[0] >> 2) & 0x3f);
  7449.         c2 = (((int)cp[0] & 0x03) << 4) + (((int)cp[1] >> 4) & 0x0f);
  7450.         c3 = (((int)cp[1] & 0x0f) << 2) + (((int)cp[2] >> 6) & 0x03);
  7451.         c4 =  ((int)cp[2] & 0x3f);
  7452.  
  7453.         *p++ = b64tab[c1];
  7454.         *p++ = b64tab[c2];
  7455.         *p++ = b64tab[c3];
  7456.         *p++ = b64tab[c4];
  7457.     }
  7458.     
  7459.     if (size == 2)
  7460.     {
  7461.         c1 = (((int)cp[0] >> 2) & 0x3f);
  7462.         c2 = (((int)cp[0] & 0x03) << 4) + (((int)cp[1] >> 4) & 0x0f);
  7463.         c3 = (((int)cp[1] & 0x0f) << 2);
  7464.  
  7465.         *p++ = b64tab[c1];
  7466.         *p++ = b64tab[c2];
  7467.         *p++ = b64tab[c3];
  7468.         *p++ = '=';
  7469.     }
  7470.     else if (size == 1)
  7471.     {
  7472.         c1 = (((int)cp[0] >> 2) & 0x3f);
  7473.         c2 = (((int)cp[0] & 0x03) << 4);
  7474.  
  7475.         *p++ = b64tab[c1];
  7476.         *p++ = b64tab[c2];
  7477.         *p++ = '=';
  7478.         *p++ = '=';
  7479.     }
  7480.     *p = '\0';
  7481.  
  7482.     return(buf);
  7483. }
  7484.  
  7485. /*
  7486. ** NSAP_NTOA -- Convert binary nsap address to ascii
  7487. ** -------------------------------------------------
  7488. **
  7489. **    Returns:
  7490. **        Pointer to string.
  7491. **
  7492. **    As per RFC 1637 an nsap address is encoded in binary form
  7493. **    in the resource record. It was unclear from RFC 1348 how
  7494. **    the encoding should be. RFC 1629 defines an upper bound
  7495. **    of 20 bytes to the size of a binary nsap address.
  7496. */
  7497.  
  7498. char *
  7499. nsap_ntoa(cp, size)
  7500. input u_char *cp;            /* current position in answer buf */
  7501. input int size;                /* number of bytes to extract */
  7502. {
  7503.     static char buf[3*MAXNSAP+1];
  7504.     register char *p;
  7505.     register int n;
  7506.     register int i;
  7507.  
  7508.     if (size > MAXNSAP)
  7509.         size = MAXNSAP;
  7510.  
  7511.     for (p = buf, i = 0; i < size; i++, cp++)
  7512.     {
  7513.         n = ((int)(*cp) >> 4) & 0x0f;
  7514.         *p++ = hexdigit(n);
  7515.         n = ((int)(*cp) >> 0) & 0x0f;
  7516.         *p++ = hexdigit(n);
  7517.  
  7518.         /* add dots for readability */
  7519.         if ((i % 2) == 0 && (i + 1) < size)
  7520.             *p++ = '.';
  7521.     }
  7522.     *p = '\0';
  7523.  
  7524.     return(buf);
  7525. }
  7526.  
  7527. /*
  7528. ** IPNG_NTOA -- Convert binary ip v6 address to ascii
  7529. ** --------------------------------------------------
  7530. **
  7531. **    Returns:
  7532. **        Pointer to string.
  7533. **
  7534. **    As per RFC 1886 an ip v6 address is encoded in binary form
  7535. **    in the resource record. The size is fixed.
  7536. */
  7537.  
  7538. char *
  7539. ipng_ntoa(cp)
  7540. input u_char *cp;            /* current position in answer buf */
  7541. {
  7542.     static char buf[5*(IPNGSIZE/2)+1];
  7543.     register char *p;
  7544.     register int n;
  7545.     register int i;
  7546.  
  7547.     for (p = buf, i = 0; i < IPNGSIZE/2; i++)
  7548.     {
  7549.         n = _getshort(cp);
  7550.         cp += INT16SZ;
  7551.  
  7552.         (void) sprintf(p, ":%X", n);
  7553.         p += strlength(p);
  7554.     }
  7555.     *p = '\0';
  7556.  
  7557.     return(buf + 1);
  7558. }
  7559.  
  7560. /*
  7561. ** PR_DATE -- Produce printable version of a clock value
  7562. ** -----------------------------------------------------
  7563. **
  7564. **    Returns:
  7565. **        Pointer to string.
  7566. **
  7567. **    The value is a standard absolute clock value.
  7568. */
  7569.  
  7570. char *
  7571. pr_date(value)
  7572. input int value;            /* the clock value to be converted */
  7573. {
  7574.     static char buf[sizeof("YYYYMMDDHHMMSS")+1];
  7575.     time_t clocktime = value;
  7576.     struct tm *t;
  7577.     
  7578.     t = gmtime(&clocktime);
  7579.     t->tm_year += 1900;
  7580.     t->tm_mon += 1;
  7581.  
  7582.     (void) sprintf(buf, "%04d%02d%02d%02d%02d%02d",
  7583.         t->tm_year, t->tm_mon, t->tm_mday,
  7584.         t->tm_hour, t->tm_min, t->tm_sec);
  7585.  
  7586.     return(buf);
  7587. }
  7588.  
  7589. /*
  7590. ** PR_TIME -- Produce printable version of a time interval
  7591. ** -------------------------------------------------------
  7592. **
  7593. **    Returns:
  7594. **        Pointer to a string version of interval.
  7595. **
  7596. **    The value is a time interval expressed in seconds.
  7597. */
  7598.  
  7599. char *
  7600. pr_time(value, brief)
  7601. input int value;            /* the interval to be converted */
  7602. input bool brief;            /* use brief format if set */
  7603. {
  7604.     static char buf[256];
  7605.     register char *p = buf;
  7606.     int week, days, hour, mins, secs;
  7607.  
  7608.     /* special cases */
  7609.     if (value < 0)
  7610.         return("negative");
  7611.     if ((value == 0) && !brief)
  7612.         return("zero seconds");
  7613.  
  7614. /*
  7615.  * Decode the components.
  7616.  */
  7617.     secs = value % 60; value /= 60;
  7618.     mins = value % 60; value /= 60;
  7619.     hour = value % 24; value /= 24;
  7620.     days = value;
  7621.  
  7622.     if (!brief)
  7623.     {
  7624.         days = value % 7; value /= 7;
  7625.         week = value;
  7626.     }
  7627.  
  7628. /*
  7629.  * Now turn it into a sexy form.
  7630.  */
  7631.     if (brief)
  7632.     {
  7633.         if (days > 0)
  7634.         {
  7635.             (void) sprintf(p, "%d+", days);
  7636.             p += strlength(p);
  7637.         }
  7638.  
  7639.         (void) sprintf(p, "%02d:%02d:%02d", hour, mins, secs);
  7640.         return(buf);
  7641.     }
  7642.  
  7643.     if (week > 0)
  7644.     {
  7645.         (void) sprintf(p, ", %d week%s", week, plural(week));
  7646.         p += strlength(p);
  7647.     }
  7648.  
  7649.     if (days > 0)
  7650.     {
  7651.         (void) sprintf(p, ", %d day%s", days, plural(days));
  7652.         p += strlength(p);
  7653.     }
  7654.  
  7655.     if (hour > 0)
  7656.     {
  7657.         (void) sprintf(p, ", %d hour%s", hour, plural(hour));
  7658.         p += strlength(p);
  7659.     }
  7660.  
  7661.     if (mins > 0)
  7662.     {
  7663.         (void) sprintf(p, ", %d minute%s", mins, plural(mins));
  7664.         p += strlength(p);
  7665.     }
  7666.  
  7667.     if (secs > 0)
  7668.     {
  7669.         (void) sprintf(p, ", %d second%s", secs, plural(secs));
  7670.         /* p += strlength(p); */
  7671.     }
  7672.  
  7673.     return(buf + 2);
  7674. }
  7675.  
  7676. /*
  7677. ** PR_SPHERICAL -- Produce printable version of a spherical location
  7678. ** -----------------------------------------------------------------
  7679. **
  7680. **    Returns:
  7681. **        Pointer to a string version of location.
  7682. **
  7683. **    The value is a spherical location (latitude or longitude)
  7684. **    expressed in thousandths of a second of arc.
  7685. **    The value 2^31 represents zero (equator or prime meridian).
  7686. */
  7687.  
  7688. char *
  7689. pr_spherical(value, pos, neg)
  7690. input int value;            /* the location to be converted */
  7691. input char *pos;            /* suffix if value positive */
  7692. input char *neg;            /* suffix if value negative */
  7693. {
  7694.     static char buf[256];
  7695.     register char *p = buf;
  7696.     char *direction;
  7697.     int degrees, minutes, seconds, fracsec;
  7698.  
  7699. /*
  7700.  * Normalize.
  7701.  */
  7702.     value -= (int)((unsigned)1 << 31);
  7703.  
  7704.     direction = pos;
  7705.     if (value < 0)
  7706.     {
  7707.         direction = neg;
  7708.         value = -value;
  7709.     }
  7710.  
  7711. /*
  7712.  * Decode the components.
  7713.  */
  7714.     fracsec = value % 1000; value /= 1000;
  7715.     seconds = value % 60;   value /= 60;
  7716.     minutes = value % 60;   value /= 60;
  7717.     degrees = value;
  7718.  
  7719. /*
  7720.  * Construct output string.
  7721.  */
  7722.     (void) sprintf(p, "%d", degrees);
  7723.     p += strlength(p);
  7724.  
  7725.     if (minutes > 0 || seconds > 0 || fracsec > 0)
  7726.     {
  7727.         (void) sprintf(p, " %02d", minutes);
  7728.         p += strlength(p);
  7729.     }
  7730.  
  7731.     if (seconds > 0 || fracsec > 0)
  7732.     {
  7733.         (void) sprintf(p, " %02d", seconds);
  7734.         p += strlength(p);
  7735.     }
  7736.  
  7737.     if (fracsec > 0)
  7738.     {
  7739.         (void) sprintf(p, ".%03d", fracsec);
  7740.         p += strlength(p);
  7741.     }
  7742.  
  7743.     (void) sprintf(p, " %s", direction);
  7744.  
  7745. #ifdef obsolete
  7746.     (void) sprintf(buf, "%d %02d %02d.%03d %s",
  7747.         degrees, minutes, seconds, fracsec, direction);
  7748. #endif
  7749.     return(buf);
  7750. }
  7751.  
  7752. /*
  7753. ** PR_VERTICAL -- Produce printable version of a vertical location
  7754. ** ---------------------------------------------------------------
  7755. **
  7756. **    Returns:
  7757. **        Pointer to a string version of location.
  7758. **
  7759. **    The value is an altitude expressed in centimeters, starting
  7760. **    from a base 100000 meters below the GPS reference spheroid.
  7761. **    This allows for the actual range [-10000000 .. 4293967296].
  7762. */
  7763.  
  7764. char *
  7765. pr_vertical(value, pos, neg)
  7766. input int value;            /* the location to be converted */
  7767. input char *pos;            /* prefix if value positive */
  7768. input char *neg;            /* prefix if value negative */
  7769. {
  7770.     static char buf[256];
  7771.     register char *p = buf;
  7772.     char *direction;
  7773.     int meters, centimeters;
  7774.     unsigned int altitude;
  7775.     unsigned int reference;
  7776.  
  7777. /*
  7778.  * Normalize.
  7779.  */
  7780.     altitude = value;
  7781.     reference = 100000*100;
  7782.  
  7783.     if (altitude < reference)
  7784.     {
  7785.         direction = neg;
  7786.         altitude = reference - altitude;
  7787.     }
  7788.     else
  7789.     {
  7790.         direction = pos;
  7791.         altitude = altitude - reference;
  7792.     }
  7793.  
  7794. /*
  7795.  * Decode the components.
  7796.  */
  7797.     centimeters = altitude % 100; altitude /= 100;
  7798.     meters = altitude;
  7799.  
  7800. /*
  7801.  * Construct output string.
  7802.  */
  7803.     (void) sprintf(p, "%s%d", direction, meters);
  7804.     p += strlength(p);
  7805.  
  7806.     if (centimeters > 0)
  7807.         (void) sprintf(p, ".%02d", centimeters);
  7808.  
  7809. #ifdef obsolete
  7810.     (void) sprintf(buf, "%s%d.%02d", direction, meters, centimeters);
  7811. #endif
  7812.     return(buf);
  7813. }
  7814.  
  7815. /*
  7816. ** PR_PRECISION -- Produce printable version of a location precision
  7817. ** -----------------------------------------------------------------
  7818. **
  7819. **    Returns:
  7820. **        Pointer to a string version of precision.
  7821. **
  7822. **    The value is a precision expressed in centimeters, encoded
  7823. **    as 4-bit mantissa and 4-bit power of 10 (each ranging 0-9).
  7824. */
  7825.  
  7826. unsigned int poweroften[10] =
  7827. {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
  7828.  
  7829. char *
  7830. pr_precision(value)
  7831. input int value;            /* the precision to be converted */
  7832. {
  7833.     static char buf[256];
  7834.     register char *p = buf;
  7835.     int meters, centimeters;
  7836.     unsigned int precision;
  7837.     register int mantissa;
  7838.     register int exponent;
  7839.  
  7840. /*
  7841.  * Normalize.
  7842.  */
  7843.     mantissa = ((value >> 4) & 0x0f) % 10;
  7844.     exponent = ((value >> 0) & 0x0f) % 10;
  7845.     precision = mantissa * poweroften[exponent];
  7846.  
  7847. /*
  7848.  * Decode the components.
  7849.  */
  7850.     centimeters = precision % 100; precision /= 100;
  7851.     meters = precision;
  7852.  
  7853. /*
  7854.  * Construct output string.
  7855.  */
  7856.     (void) sprintf(p, "%d", meters);
  7857.     p += strlength(p);
  7858.  
  7859.     if (centimeters > 0)
  7860.         (void) sprintf(p, ".%02d", centimeters);
  7861.  
  7862. #ifdef obsolete
  7863.     (void) sprintf(buf, "%d.%02d", meters, centimeters);
  7864. #endif
  7865.     return(buf);
  7866. }
  7867.